How to set post parameters on using Alamofire in swift - swift

I am using Alamofire in swift to send http request/post to server. Below is the code I used in swift.
Alamofire.request(.POST, "http://localhost:8080/hello", headers: [ACCESS_TOKEN:token, "Content-Type":"application/x-www-form-urlencoded" ],
parameters:["friend_id" : friendId, "skill_id" : skillId]).response(completionHandler: {
(request, response, data, error) in
print(request)
print(response)
print(data)
print(error)
})
Below is the code defined in server side:
#POST
#Path("/hello")
#Produces(MediaType.APPLICATION_JSON)
public Response nominateSkill(#Context HttpServletRequest request, #FormParam("friend_id") long friendId, #FormParam("skill_id") int skillId) {
// ...
}
When I run the swift code, I always got below error message in server side:
A servlet request to the URI http://localhost:8080/hello contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.
I think the problem would be coursed by the swift code which didn't set the parameter correctly. But I don't know how to set them correctly?

I found the solution after some search. I need to add "encoding: .URL" on the request method like below:
Alamofire.request(.POST, "http://localhost:8080/hello", headers: [ACCESS_TOKEN:token, "Content-Type":"application/x-www-form-urlencoded" ],
parameters:["friend_id" : friendId, "skill_id" : skillId],
encoding: .URL).response(completionHandler: {
(request, response, data, error) in
print(request)
print(response)
print(data)
print(error)
})

Your swift code seems fine. Make sure on which side problem is occur. You can try https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en to test the api and make sure api doen't have any issues.
You may also try to change data type of friend_id and skill_id to string in server side and run again.

Related

How to get error message from response body when use Alamofire.download() request

AF.download(url, parameters: params, to: destination)
.validate(statusCode: [200])
.response { response in
switch response.result {
case .success(let url):
print("ok", url)
case .failure(let err):
print(err.localizedDescription)
}
}
When server response some error code like 4xx, 5xx, it will print "Response status code was unacceptable: xxx.", but I want the detail message in response body(server send plain text when error), I read some post that said we can retrieve response message with "response.data" but if use AF.download method, there isn't have "data" property with response object(Alamofire.AFDownloadResponse). so, is there any way to figure it out?
Alamofire's DownloadResponse contains a fileURL: URL? property which can be used to load the downloaded data from disk even when validation or other actions produce a failure result in the response.
This is from Alamofire Source Code;
The debug textual representation used when written to an output stream, which includes (if available) a summary of the URLRequest, the request's headers and body (if decodable as a String below 100KB); the HTTPURLResponse's status code, headers, and body; the duration of the network and serialization actions; and the Result of serialization.
Response debug description has status code information. So, the response should have status code information.
Also when I check source code, I see this part;
static func description(of response: HTTPURLResponse) -> String {
"""
[Response]:
[Status Code]: \(response.statusCode)
\(DebugDescription.description(for: response.headers).indentingNewlines())
"""
}
So, response.status should give what your want. Good luck.

Alamofire callback caching

I've been thinking of using Alamofire for my network requests. I've read somewhere that Alamofire does callback caching. What I mean by that is when I do multiple GETs to the same URL, but only 1 does the actual request and both just receive the response. This way I could avoid multiple network calls to same resource, but have the resource in both callbacks
I just cannot find any truth of this concept in their documentation.
So my question is this possible? And if so is this just a behind the scene thing or how do I use it?
I've been testing with the following code from their documentation:
func x() {
Alamofire.request("https://httpbin.org/get").responseJSON { response in
print("Request: \(String(describing: response.request))") // original url request
print("Response: \(String(describing: response.response))") // http url response
print("Result: \(response.result)") // response serialization result
print("Timeline: \(response.timeline)")
if let json = response.result.value {
print("JSON: \(json)") // serialized json response
}
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
print("Data: \(utf8Text)") // original server data as UTF8 string
}
}
}
x()
x()
x()
Method x is called 3 times and 3 GET's are fired over the network.
I'm not sure what you've read, but Alamofire doesn't have any sort of request deduplication. AlamofireImage does, for image requests, but the feature only exists in that library. However, Alamofire does support standard HTTP caching methods, so if you request the same resource twice, and the server properly returned one of the caching headers, Alamofire should accept the locally cached copy. This is done through the standard URLCache class, so you should read its documentation to learn more.

POST request not working in swift3 with alamofire

I am using Alamofire for calling my API .
below is is the code.
func alamofirePost() {
let headers: HTTPHeaders = [ "content-type": "x-www-form-urlencoded"]
let todosEndpoint: String = "http://54.244.108.186:4000/api/post_upc"
let newTodo: [String: Any] = ["UPC": codeTextView.text, "DATE_TIME": currentTime() ]
print("i am in alamo")
Alamofire.request(todosEndpoint, method: .post, parameters: newTodo ,encoding: JSONEncoding.default,headers: headers )
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling POST on /todos/1")
print(response)
print(response.result.error!)
return
}
when i call the function , it is trying to inserting null values in the database
INSERT INTO `UPC`(`UPC`,`DATE_TIME`) VALUES (NULL,NULL)
Below is the response when i do in postman app.
can someone please help
Firstly in your Postman request you are POSTing your body as x-www-form-urlencoded but in your Swift example you are specifying that header as well. BUT you're actually submitting your POST body as a JSON payload. In contrast, your Postman request is a set of key/value pairs.
Additionally, the two keys appear to be named differently from your Swift example and your Postman example.
Swift uses UPC and DATE_TIME while Postman has upc_app and dttm_app so at a minimum you'll want to ensure you send along what your API expects

Cannot call value of non-function type 'HTTPURLResponse?' Alamofire 4, Swift 3

I want to use Alamofire to send an email with Mailgun. I'm using the below code to send the request, but I'm getting error Cannot call value of non-function type 'HTTPURLResponse?' on line starting with .response.
How can I fix this? I'm trying to replicate the code found here but update it for Swift 3. I'm trying to send an email using Mailgun and Alamofire.
https://gist.github.com/makzan/11e8605f85352abf8dc1/
Thanks!
Alamofire.request(url, method: .post, parameters: parameters)
.authenticate(user: "api", password: key)
.response{ (request, response, data, error) in
println(request)
println(response)
println(error)
}
}
It's worth taking a look at the Alamofire migration pages for these sorts of issues.
You'll see there that responses are now handled like so:
// Alamofire 3
Alamofire.request(.GET, urlString).response { request, response, data, error in
print(request)
print(response)
print(data)
print(error)
}
// Alamofire 4
Alamofire.request(urlString).response { response in // method defaults to `.get`
debugPrint(response)
}

How can I retrieve the status message of a request made with Alamofire?

The server that I am using returns error messages in the HTTP status message. For example, it will return "400 User already exists" rather than "400 Bad Request".
I would like to access the string "User already exists" in the response method called by Alamofire. However, I cannot find any way to access this string.
I found this question on StackOverflow already: Swift Alamofire: How to get the HTTP response status code
Unfortunately, no one gives an answer to the question. :(
Here is where Chrome shows where the error is:
I would suggest trying to print out all the possible data fields that you are given and see what you can find. Please try the following example and see if that sheds any light.
let URL = NSURL(string: "your/url/to/somewhere")!
let parameters = ["foo": "bar"]
Alamofire.request(.POST, URL, parameters: parameters)
.response { request, response, data, error in
println("Request: \(request)")
println("Response: \(response)")
println("Error: \(error)")
if let data = data as? NSData {
println("Data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
}
}
Return response in json format from the server and then i think you'll be able to get the appropriate status.
I've implemented that thing using php codeigniter..from where my response is like
$response['status'] = 'user_already_exists';
$this->response($response, 400);
Now in swift you can go with this
Alamofire.request(.POST,URL, parameters:parameters) .responseJSON
{
(request, response, data, error) in
var json = JSON(data!) //I've used swiftyJSON for reading json response
let status = json["status"].stringValue
println("Status : \(status)")
}
Hope this may help you.