Sending JSON or SwiftyJSON through Alamofire POST - ios

Similar questions to this have been posted before but with slight differences, namely:
Alamofire: Sending JSON as request parameter
POST multiple json objects in Alamofire POST method - Swift/IOS
Sending json array via Alamofire
being the last one, the closest to my current problem. However, this solution is not working for me.
The problem I am facing is that I'm trying to send through an Alamofire POST request, a JSON that I've built using SwiftyJSON. Like so:
let url = NSURL(string: orderProductsEndpoint)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue(requestToken, forHTTPHeaderField: "Authorization:")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let params = [ json.object ]
print(params)
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject( params, options: [])
Alamofire.request(request)
.responseString{ response in
switch response.result {
case .Success(let value):
print("gut")
print(value)
case .Failure(let error):
print("not gut")
print(error)
}
}
However, this is not working well because the API that I'm communicating with doesn't seem to recognize well the parameters that I'm sending.
But then I noticed that what I am sending is not a valid JSON. This is what I am sending:
[{
car = (
{
cant = 2;
id = 6;
name = "Saudi Plate";
},
{
cant = 1;
id = 5;
name = "Beef Wrap";
}
);
idUser = 58;
"total_loyalty_points" = 4200;
"total_price" = 42000;}]
But before converting my JSON to an object using
let params = [ json.object ]
It was a valid JSON validated through JSONLint and it looks like this
{
"total_price" : 42000,
"car" : [
{
"id" : "6",
"cant" : 2,
"name" : "Saudi Plate"
},
{
"id" : "5",
"cant" : 1,
"name" : "Beef Wrap"
}
],
"idUser" : 58,
"total_loyalty_points" : 4200
}
So the problem is that I was forced to change the structure of the JSON because it seems to be the only way to send it through Alamofire, by converting it into an object. Is there a way to actually send raw JSON through Alamofire?

Try setting the json encoding for your parameters in the Alamofire request.
Alamofire.request("http://...", method: HTTPMethod.post, parameters: parameters, encoding: JSONEncoding.default, headers: nil)
.responseJSON(completionHandler: {(response) in ... })
https://github.com/Alamofire/Alamofire#json-encoding

Try to get your params as Alamofire parameters i.e [String : Any].
Basically you want to send raw json with post method.
Below function will do a post request with raw json. Also this is with generics
func nwCallRawJSon<T: Decodable>(url : String, param : [String : Any],decodable: T.Type,onCompletion: #escaping (T?,Error?) -> Void){
AF.request(url, method: .post, parameters : param, encoding: JSONEncoding.default, headers: nil).validate(contentType: ["application/json"]).responseDecodable { (response: DataResponse<T,AFError>) in
switch response.result {
case .success(let data):
onCompletion(data,nil)
case .failure(let error):
onCompletion(nil,error)
}
}
}

Related

Failed response from **Alamofire** in swift 5

I'm using Alamofire class for api calling. Api is working properly in Postman
please check below two screenshots for reference,
in first image data is passing inside raw body
in second image data is passing inside Headers field
now i'm using this code to call API
//for params i'm sending below parameters
//["phoneNumber":"911234567890", "countryCode" : "91"]
let headers: HTTPHeaders = [
"deviceId" : deviceId,
"osVersion": osVersion,
"deviceType": deviceType,
"resolution":resolution,
"buildNumber":buildNumber]
AF.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers:headers).responseData { (response) in
switch response.result {
case .success(let data):
do {
//let asJSON = try JSONSerialization.jsonObject(with: data)
let asJSON = try JSONSerialization.jsonObject(with: data, options: [.fragmentsAllowed])
// success
print(asJSON)
let res : NSDictionary = (asJSON as AnyObject) as! NSDictionary
successBlock(res)
} catch { // error
print("decoding error:\n\(error)")
}
case .failure(let error):
print(error)
failure(error)
}
}
in all other project above code is working fine for api calling, but here i'm getting below error
{ code = 500; data = ""; message = "Failed to convert value of type 'java.lang.String' to required type 'java.util.Locale'; nested exception is java.lang.IllegalArgumentException: Locale part "en;q=1.0" contains invalid characters"; …………………… NamedValueMethodArgumentResolver.java:125)\n\t... 97 more\n"; status = "INTERNAL_SERVER_ERROR"; timestamp = "01-03-2022 07:55:20"; }
i've try several methods like URLEncoding.default, passing custom header, create custom raw request & passed header inside but nothing works,
AnyOne have solution for this issue?
Thanks in Advance.
As it is throwing error related to Local, I think some language is defined and it doesn't accept * for Accept-Language header, try sending "en" in the header Accept-Language.
Check subtags for language:
http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry :
Test Code:
func callAPI() {
let params: Parameters = ["phoneNumber":"911234567890", "countryCode" : "91"]
let headers = [
"deviceId" : "jdhcbkerfjkr",
"osVersion": "3.2.3",
"deviceType": "ANDROID",
"resolution": "122x122",
"buildNumber": "3.2.1",
"Accept-Language": "en"]
AF.request("[Test-URL]",
method: .post,
parameters: params,
encoding: JSONEncoding.default,
headers: HTTPHeaders.init(headers)).response { response in
print(String(data: response.data!, encoding: .utf8)!)
}
}

Pass JSON object in GET request: iOS

I want to add the JSON object in GET request with URL. Please refer below URL.
https://testdata.com/xyz/&form={"id":"12", "data": "3"}
I am getting nil while converting String to URL
let serviceUrl = URL(string: url)
Thanks in advance.
I was already tried below solution but unfortunately no luck.
JSONSerialization.data
converting to string with utf8
removed whitespaces if any
addingPercentEncoding with URL host allowed
It's not recommended, to send a request body with GET request. GET request means to fetch all the resources/content that this URL has to offer. If they are parsing the GET body on server side, it's against the semantics. But if you really need to do it. Use Almofire. Here's a Sample Code.
let parameters : [String : Any] = [
"id":"12",
"data":"3"
]
func getContent(parameters: [String: Any]) {
Alamofire.request("http://18.218.235.193:3000/user/securedtoken", method:
.get, parameters: parameters, encoding: JSONEncoding.default)
.responseObject {(response:
DataResponse<YOUR RESPONSE MODEL HERE>) in
let response = response.result.value
//Do Something (Success)
}
}
I recommend you to use Alamofire library. You can do what you want using following code snippet
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["form": ["id": 12, "data": 3]])
.response { request, response, data, error in
print(request)
print(response)
print(error)
}

Alamofire 4 missing parameters in POST

Spent hours on this with no success.
I'm using Alamofire to make a HTTP POST to back end server which requires some parameters to be supplied with request.
I'm successfully hitting the server but the server is responding with a 500 stating no parameters were sent?
I've tried most of the SO solutions (changing the encoding type, setting parameters as NSDict, etc) but with no success.
Any help greatly appreciated.
PS its Swift3 with Alamofire 4
Code:
let params: [String: String] = ["deviceID": "Some device ID",
"email": "email","password": "password","userid": "1234",
"username":"gordon"]
let request_params: Parameters = ["LoginUser" : params]
let url = "https://myserver/LogIn" as String
Alamofire.request(url, method: .post, parameters: request_params, encoding: URLEncoding.default, headers: [
"Content-Type": "application/x-www-form-urlencoded"
]).responseString { (response:DataResponse<String>) in
switch(response.result) {
case.success(let data):
print("success",data)
print(response.response)
case.failure(let error):
print("Failed!",error)
}
}
Update:
Below is the body of the POST, it looks like this is where the problem exists:
Alamofire POST body (from above code) -
(LoginUser%5BdeviceID%5D=12345&LoginUser%5Bemail%5D=gordon%40test.com&LoginUser%5Buserid%5D=00000000-0000-0000-0000-000000000000&LoginUser%5Bpassword%5D=testPassword&LoginUser%5Busername%5D=gordon)
It should be something like (ignoring the encoding values):
This is a functional post body-
LoginUser=%7B%22deviceID%22%3A%22%22%2C%22email%22%3A%22gordon%40test.com%22%2C%22password%22%3A%22testPassword%22%2C%22userid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22username%22%3A%22gordon%22%7D
As you can see the Alamofire post seems to concatenate the LoginUser to start of each attribute? Also missing the LoginUser= at start??
Try to use JSONEncoding.default instead of URLEncoding.default
OK so I got this working with the below code, would be very interested in understanding if this is the most efficient means of posting param?
let params: NSMutableDictionary? = ["deviceID": "someDeviceID",
"email": "emailAddress","password": "aSecret","userid": "12345",
"username":"gordon"]
let url = "https://serverAdrress" as String
let data = try! JSONSerialization.data(withJSONObject: params!, options: JSONSerialization.WritingOptions.prettyPrinted)
let json: NSString! = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
let request_params: Parameters = ["LoginUser" : json as Any]
Alamofire.request(url, method: .post, parameters: request_params, encoding: URLEncoding.httpBody, headers: [
"Content-Type": "application/x-www-form-urlencoded"
]).responseString { (response:DataResponse<String>) in
switch(response.result) {
case.success(let data):
print("success",data)
print(NSString(data: (response.request?.httpBody)!, encoding: String.Encoding.utf8.rawValue))
print(response.response)
case.failure(let error):
print("Not Success",error)
}
}

Postman Body Raw Request To Swift Alamofire

I'm trying to re-create this Postman settings for posting in Alamofire. This is my first time to see an API that requires both Parameters and a body with Raw Json.
I'm done with gathering and formatting my data (either in Json using SwiftyJSON or Dictionary [String : Any] / Parameters) for the said requirement.
While I did see a similar question to this: Postman request to Alamofire request but it doesn't have a valid answer. Assume that I'm quite experienced with posting/getting/etc data from various API but I just don't know how to pass raw data just like in the photo above. Please check out my comments too in the code.
Here's what I'm doing with my function for this request:
/** Apply to job with Shift.
* This service function creates a json data for applying.
*/
func someFuncService(_ job: Job, daySchedules: [(Int, String, Schedule)], withBlock completion: #escaping JobServiceCommonCallBack) {
AuthService.someFunc { (currentCustomer, accessToken) in
guard let lalala = currentCustomer?.id,
let accessT = accessToken else {
completion(LalaErrors.currentCustomerError)
return
}
guard let jobId = job.id else {
completion(LalaErrors.modelError)
return
}
let coreService = LalaCoreService()
let applicantEndpoint = LalaCoreService.Endpoint.Applicant
let parameters = [
"param1" : customerId,
"param2" : jobId,
"accessToken" : accessToken,
"shift" : self.generateDataFromDaySchedules(daySchedules) // this returns [String : Any], can be printed into Json using JSON(x)
] as Parameters
GPLog(classSender: self, log: "FINAL PARAMETER: \(parameters)")
coreService.request = Alamofire.request(
applicantEndpoint,
method: .post,
parameters: parameters,
encoding: URLEncoding.default, // I already have tried .httpbody too.
headers: nil
)
coreService.request {
(response, result) in
if let error = result?.error {
if response!.statusCode == 500 {
completion(GPKitError.newError(description: "Failed to apply. Please contact the admin."))
return
}
completion(error)
return
}
// Success
completion(nil)
return
}
}
}
EDIT: So the question is, what I'm doing wrong here? API returns me status code 500 internal server error.
coreService.request = Alamofire.request(
applicantEndpoint,
method: .post,
parameters: parameters,
encoding: URLEncoding.default, // I already have tried .httpbody too.
headers: nil
)
should be
coreService.request = Alamofire.request(
applicantEndpoint + accessToken,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: nil
)

Alamofire invalid value around character 0

Alamofire.request(.GET, "url").authenticate(user: "", password: "").responseJSON() {
(request, response, json, error) in
println(error)
println(json)
}
This is my request with Alamofire, for a certain request it sometime works, but sometimes i get:
Optional(Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (Invalid value around character 0.) UserInfo=0x78e74b80 {NSDebugDescription=Invalid value around character 0.})
I've read that this can be due to invalid JSON, but the response is a static json string that i have validated in JSON validator as valid. It does contain å ä ö characters and some HTML.
Why am i getting this error sometimes?
I also faced same issue. I tried responseString instead of responseJSON and it worked. I guess this is a bug in Alamofire with using it with django.
In my case , my server URL was incorrect. Check your server URL !!
I got same error while uploading image in multipart form in Alamofire as i was using
multipartFormData.appendBodyPart(data: image1Data, name: "file")
i fixed by replacing by
multipartFormData.appendBodyPart(data: image1Data, name: "file", fileName: "myImage.png", mimeType: "image/png")
Hope this help someone.
May this Help YOu
Alamofire.request(.GET, "YOUR_URL")
.validate()
.responseString { response in
print("Success: \(response.result.isSuccess)")
print("Response String: \(response.result.value)")
}
The same issue happened to me and it actually ended up being a server issue since the content type wasn't set.
Adding
.validate(contentType: ["application/json"])
To the request chain solved it for me
Alamofire.request(.GET, "url")
.validate(contentType: ["application/json"])
.authenticate(user: "", password: "")
.responseJSON() { response in
switch response.result {
case .Success:
print("It worked!")
print(response.result.value)
case .Failure(let error):
print(error)
}
}
I got the same error. But i found the solution for it.
NOTE 1: "It is not Alarmofire error", it's bcouse of server error.
NOTE 2: You don't need to change "responseJSON" to "responseString".
public func fetchDataFromServerUsingXWWWFormUrlencoded(parameter:NSDictionary, completionHandler: #escaping (_ result:NSDictionary) -> Void) -> Void {
let headers = ["Content-Type": "application/x-www-form-urlencoded"]
let completeURL = "http://the_complete_url_here"
Alamofire.request(completeURL, method: .post, parameters: (parameter as! Parameters), encoding: URLEncoding.default, headers: headers).responseJSON { response in
if let JSON = response.result.value {
print("JSON: \(JSON)") // your JSONResponse result
completionHandler(JSON as! NSDictionary)
}
else {
print(response.result.error!)
}
}
}
This is how I managed to resolve the Invalid 3840 Err.
The error log
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
It was with Encoding Type used in the Request, The Encoding Type used should be acceptedin your Server-Side.
In-order to know the Encoding I had to run through all the Encoding Types:
default/
methodDependent/
queryString/
httpBody
let headers: HTTPHeaders = [
"Authorization": "Info XXX",
"Accept": "application/json",
"Content-Type" :"application/json"
]
let parameters:Parameters = [
"items": [
"item1" : value,
"item2": value,
"item3" : value
]
]
Alamofire.request("URL",method: .post, parameters: parameters,encoding:URLEncoding.queryString, headers: headers).responseJSON { response in
debugPrint(response)
}
It also depends upon the response we are recieving use the appropriate
responseString
responseJSON
responseData
If the response is not a JSON & just string in response use responseString
Example: in-case of login/ create token API :
"20dsoqs0287349y4ka85u6f24gmr6pah"
responseString
I solved using this as header:
let header = ["Content-Type": "application/json",
"accept": "application/json"]
In my case, there was an extra / in the URL .
Maybe it is too late but I solved this problem in another way not mentioned here:
When you use .responseJSON(), you must set the response header with content-type = application/json, if not, it'll crash even if your body is a valid JSON. So, maybe your response header are empty or using another content-type.
Make sure your response header is set with content-type = application/json to .responseJSON() in Alamofire work properly.
Hey guys this is what I found to be my issue: I was calling Alamofire via a function to Authenticate Users: I used the function "Login User" With the parameters that would be called from the "body"(email: String, password: String) That would be passed
my errr was exactly:
optional(alamofire.aferror.responseserializationfailed(alamofire.aferror.responseserializationfailurereason.jsonserializationfailed(error domain=nscocoaerrordomain code=3840 "invalid value around character 0." userinfo={nsdebugdescription=invalid value around character 0
character 0 is the key here: meaning the the call for the "email" was not matching the parameters: See the code below
func loginUser(email: String, password: String, completed: #escaping downloadComplete) {
let lowerCasedEmail = email.lowercased()
let header = [
"Content-Type" : "application/json; charset=utf-8"
]
let body: [String: Any] = [
"email": lowerCasedEmail,
"password": password
]
Alamofire.request(LOGIN_USER, method: .post, parameters: body, encoding: JSONEncoding.default, headers: header).responseJSON { (response) in
if response.result.error == nil {
if let data = response.result.value as? Dictionary<String, AnyObject> {
if let email = data["user"] as? String {
self.userEmail = email
print(self.userEmail)
}
if let token = data["token"] as? String {
self.token_Key = token
print(self.token_Key)
}
"email" in function parameters must match the let "email" when parsing then it will work..I no longer got the error...And character 0 was the "email" in the "body" parameter for the Alamofire request:
Hope this helps
I was sending the improper type (String) to the server in my parameters (needed to be an Int).
Error was resolved after adding encoding: JSONEncoding.default with Alamofire.
Alamofire.request(urlString, method: .post, parameters:
parameters,encoding:
JSONEncoding.default, headers: nil).responseJSON {
response in
switch response.result {
case .success:
print(response)
break
case .failure(let error):
print(error)
}
}
The application I was working on this morning had the same error. I believed it to be a server side error since I was unable to upload a user image.
However, upon checking my custom API, I realized that after adding an SSL certificate to my website that I had not updated the api.swift URLs, the data was unable to post:
let HOME_URL = "http://sitename.io"
let BASE_URL = "http://sitename.io/api"
let UPLOAD_URL = "http://sitename.io/api/user/upload"
I changed the URL's to https://. Problem solved.
In my case I have to add this Key: "Accept":"application/json" to my header request.
Something like this:
let Auth_header: [String:String] = ["Accept":"application/json", "Content-Type" : "application/json", "Authorization":"Bearer MyToken"]
I hope that this can help someone.
I face same issue and problem is in params.
let params = [kService: service,
kUserPath: companyModal.directory_path,
kCompanyDomain: UserDefaults.companyDomain,
kImageObject: imageString,
kEntryArray: jsonString,
kUserToken: UserDefaults.authToken] as [String : Any]
companyModal.directory_path is url. it coerced from string to any which create issues at server side. To resolve this issue I have to give default value which make it string value.
let params = [kService: kGetSingleEntry,
kUserPath: companyModal.directory_path ?? "",
kCompanyDomain: UserDefaults.companyDomain,
kUserToken: UserDefaults.authToken,
kEntryId: id,
] as [String: Any]
Probably you have "/" at the end of your path. If it is not GET request, you shouldn't put "/" at the end, otherwise you'll get the error
I Changed mimeType from "mov" to "multipart/form-data".
Alamofire.upload(multipartFormData: { (multipartFormData) in
do {
let data = try Data(contentsOf: videoUrl, options: .mappedIfSafe)
let fileName = String(format: "ios-video_%#.mov ", profileID)
multipartFormData.append(data, withName: "video", fileName: fileName, mimeType: "multipart/form-data")
} catch {
completion("Error")
}
}, usingThreshold: .init(), to: url,
method: .put,
headers: header)
Worked for me.. :)
For my case:
let header = ["Authorization": "Bearer \(Authserices.instance.tokenid)"]
I forgot the space before \ (after Bearer)
In my case error was due to duplicate email. You can recheck your API on postman to see if response there is OK or not.
In my case, I tried using Postman to get API and this error come from backend.

Resources