Alamofire error with JSON response - swift

I have been struggling with Alamofire issue for days and I'm not sure if it's from the backend or the way I structure my code.
Here is the issue:
when I text my API with Postman I get the correct response if I hit the params button and add the parameters Notice the lower body is empty but the upper one is filled with parameters
However, when I use the lower parameters with the same info I get an error with no JSON. Also same error appears in Xcode when I try to call the API with the same link
this is Xcode Alamofire error
FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
and here is Postman error
and finally this is my code to call API:
let urlStr = "api/client/meal_add"
let url = URL(string: urlStr)
let para = ["meal_id": "31",
"user_id": "2",
"qty":"2"]
let headers: HTTPHeaders = [
"Auth": "Auth" // Edited for security
]
Alamofire.request(url!, method: .post, parameters: para,encoding: URLEncoding.default, headers: headers).responseJSON { response in
print(response)
print(response.result.debugDescription)
if let value : AnyObject = response.result.value as AnyObject {
it used to work perfectly 5 days ago but I have no idea why it stoped. Also In other View Controllers I do HTTP calls to the same API and the responses have no issues, only this one.

First, I want to talk about the difference between HTTP get and post request. Get request is putting parameters in url. They are appended to the url in this format
URL?key1=value1&key2=value2
The RESTful hanlder for that URL will then parse the key value pair and use them. When you click on the param button in your postman, it actuall doing this append param to url thing. However this get into problem when you have lots of param. Usually, an url will have some problem if it exceeds length 8000. So a post request is actually nesting the parameters inside the request, not on the url. So normally in a post request, you will only see the URL, not the ?key1=value1&key2=value2 part.
Back to your problem, I have no idea how your server side handles this post request with parameters in url but since an empty post request with param in url works, in your swift code, you can simply append the param in your url and do a post request with no parameters.
let urlStr = "api/client/meal_add?meal_id=31&user_id=2&qty=2"
let url = URL(string: urlStr)
Alamofire.request(url!, method: .post, parameters: [],encoding: URLEncoding.default, headers: headers).responseJSON { response in
Moving forward, I strongly recommand you to have a look at your server side to make sure your post request is written in the correct way

Related

Alamofire with Swift using a Get

I am using Alamofire with Swift 5 and using a get to send some parameters while a Post works the following fails, any idea of how this should be used. If I remove the parameters it works .
let parameters:Parameters = ["SiteKey": "abcdef"]
AF.request(url, method: .get,parameters:parameters,encoding: JSONEncoding.default,headers:headers )
Any help is appreciated
It's clearly implied from the results that you've got. A GET request cannot contain parameters in its body, a POST request can. Get request should be something when you paste the URL in a browser and you should get the response in the browser.
In your case it's either not GET request or you need to send the parameters as url-encoded.
AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: headers)

Error fetch image from storage with message 'Alamofire.AFError.ResponseValidationFailureReason.unacceptableContentType'

I attemp to fetch image from Firebase storage, but have error message:
Alamofire.AFError.responseValidationFailed(reason: Alamofire.AFError.ResponseValidationFailureReason.unacceptableContentType(acceptableContentTypes: ["image/x-xbitmap", "image/jpeg", "application/octet-stream", "image/gif", "image/ico", "image/tiff", "image/x-icon", "image/bmp", "image/x-bmp", "image/x-win-bitmap", "image/png", "image/x-ms-bmp"], responseContentType: "application/json")
My url looks like this: https://firebasestorage.googleapis.com/v0/b/####/o/executors/o4uAQa158nXTvJ5omuxqcRb0e793/products/7DDCEEAC-ED54-4910-B93D-5E40BF411B80
I can download this image via browser.
My image has MIME-type 'image/jpeg':
I found the same situation:
Response Content-Type was missing and acceptable content types
Make sure you set alamofire acceptable content types
Image Response Serializers
These hints didn't help me to fix my bug.
Version of pod:
Alamofire: 5.0.2
AlamofireImage 4.0.2
Initially I used AlamofireImage: productImageView.af.setImage(withURL: url), but it didn't work. Then I began using Alamofire. And into request I pass MIME-type image/jpeg like Content-Type:
And I decided to use this approach to fix bug, but has the same error and I don't understand why(from docs):
If you can see in error-message I have:
responseContentType: "application/json"
So does it have any side effect to fetch image? What I do wrong at all?
Link should be
https://firebasestorage.googleapis.com/v0/b/projectname/o/image.png?alt=media&token=auth_token
replace projectname , image name and token to yours
First, your request headers have nothing do with whether the response is valid, so adding image/jpeg there won't help. Second, your response is return an application/json content type, so adding image/jpeg to the acceptable content types won't help (and image/jpeg is already acceptable). (As an aside, you need to import AlamofireImage to get addAcceptableImageContentTypes to work.)
In the end, you should ensure you're getting the response you expect, as an application/json content type implies you're getting a JSON body, not an image fro your request. When I request the URL you posted, I get this JSON response:
{
"error": {
"code": 400,
"message": "Invalid HTTP method/URL pair."
}
}
So most likely you need to double check how you're supposed to be making the request.

How to set Content-Type in swift3 alamofire

I am sending data in JSON with content-type JSON but this shows me the content-type XML.
So the server could not read my request.
Also, that is the post request
The problem is that you are using .responseJSON which tells Alamofire that the response would contain JSON. Since the response is XML and not JSON in your case, Alamofire would throw an error. What you need instead is not to specify the response type and then an XMLParser to parse the data. One option is SWXMLHash. Your updated code would look something like this
Alamofire.request(request)
.response { response in
var xml = SWXMLHash.parse(response.data!)
}
Basically, this is not an error of content-type. this is an error of data type.
I send the all value in the string but there is need to send the data with data type.
When I request with data type it automatically changed content-type in JSON.

Preventing NSURLSession default HTTP headers

I'm trying to craft a very specific HTTP request to a server (ie. defining the exact set of HTTP headers), but NSURLSession keeps "helpfully" inserting a bunch of HTTP headers like Accept, Accept-Language and Accept-Encoding.
Consider the following playground (Swift 2.x) which sends a request to a service that just echos the HTTP headers that were sent:
import Foundation
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let url = NSURL(string: "http://httpbin.org/headers")!
let request = NSMutableURLRequest(URL: url, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 30000)
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let session = NSURLSession(configuration: configuration)
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
XCPlaygroundPage.currentPage.finishExecution()
}
task.resume()
You can see that there are three Accept headers being sent. How can I prevent that?
I've tried setting the header using request.setValue(nil, forHTTPHeaderField: "Accept-Language") but that gets ignored. Tried setting it to "", but no good. I've also tried manipulating the HTTPAdditionalHeaders property on NSURLSessionConfiguration, but no love.
How do I get NSURLSession to not be quite so helpful?
I doubt what you're asking for is possible. NSURLSession (and NSURLConnection) automatically provide a number of headers, and that's one of them.
There's also no valid reason to remove them. All three of those headers have been part of the spec since the original HTTP/0.9 spec (https://www.w3.org/Protocols/HTTP/HTRQ_Headers.html). There's absolutely no excuse for any server not either handling those correctly or ignoring them outright.
With that said, if you provide the wrong value for those fields (and the default may be wrong), the server may refuse to give you results. To solve that problem, first figure out what type of data the server is actually going to provide, and specify that value in the Accept header instead of the default.
For example, you might set Accept to "application/json" or one of the other variants (What is the correct JSON content type?) if you're expecting JSON data.
That said, if you really must avoid having those headers sent, you can always open a socket, construct the request manually, and send it. Assuming the server doesn't require chunked encoding, it is pretty easy to do. (Chunked encoding, however, is a horror of Herculean proportions, so if your server sends that back, you'll pretty much have to resort to adding libcurl into your project and using that to make requests instead.)

Can Alamofire call a different response serializer depending on the content-type of the response?

Depending on its mood and information we send in the request, our server might send back an empty-bodied 204 response with content type text/plain or something else like a 400-series response with an application/json body detailing the error. How should we handle this?
We thought something like this:
Alamofire.request(request)
.responseString({ (request, response, string, error) -> Void in
// Happy dance
})
.responseSwiftyJSON({ (request, response, json, error) -> Void in
// Parse the error out of the json response and inform the user
})
... but it seems all the chained response handlers are executed. Is there a way to say "only call this one for a specific error type" or "only call this one for a specific response code"?
Are we missing something about how Alamofire is meant to work?