iOS : http Post using swift - ios

I figured it out solution at the bottom
I am trying to make an HTTP post request to my server. Here's what I did
var request : NSMutableURLRequest = NSMutableURLRequest(URL : NSURL(string : "myURL")
let session : NSURLSession = NSURLSession.sharedSession()
request.allHTTPHeaderFields = (headers as [NSObject : AnyObject])
request.HTTPShouldHandleCookies = true
request.HTTPMethod = "POST"
var postData = "frontend=iOS"
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
NSHTTPCookieStorage.sharedHTTPCookieStorage().cookieAcceptPolicy = NSHTTPCookieAcceptPolicy.Always
println(request.allHTTPHeaderFields)
println(request.HTTPBody)
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data)
println(json)
onCompletion(json, error)
})
task.resume()
this is not setting the HTTPRequest.POST
I tried printing the request to the server on the server side. IT said post was empty
POST : [QueryDict : {}]
What am I missing here? Any help is appreciated
Solution :
I mistakenly set the content-value to application/json when in fact it
was not a json body. Removing it solved the problem

use https://github.com/Alamofire/Alamofire
easy networking :)
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
you can use all of the below.
public enum Method: String {
case OPTIONS = "OPTIONS"
case GET = "GET"
case HEAD = "HEAD"
case POST = "POST"
case PUT = "PUT"
case PATCH = "PATCH"
case DELETE = "DELETE"
case TRACE = "TRACE"
case CONNECT = "CONNECT"
}

Heres the method I used in my logging library: https://github.com/goktugyil/QorumLogs
var url = NSURL(string: urlstring)
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding)
var connection = NSURLConnection(request: request, delegate: nil, startImmediately: true)
See How to escape the HTTP params in Swift on the way to correctly encode key-value pairs into the data string.

Related

URLSession sends GET request instead of POST

That's how I'm doing a POST request
var request = URLRequest(url: url)
let methodString = mehtod.rawValue
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
if let headers = headers {
request.set(headers: headers)
}
if let parameters = parameters {
do {
let postParams = try JSONEncoder().encode(parameters)
let postData = postParams
request.httpBody = postData
}
catch {
print("error")
}
}
let session = URLSession.shared
print(request)
print(request.allHTTPHeaderFields)
print(String(data: request.httpBody!, encoding: .utf8)!)
print(request.httpMethod)
session.dataTask(with: request) { (data, response, error) in
let result: Result<Data>
if let data = data {
result = .success(data)
}
else if let error = error {
result = .failure(error)
}
else {
result = .failure(RESTError.unknownError)
}
completion(result)
}.resume()
And this is what I see in Charles
I'm trying to send POST but somehow I'm sending GET request.
Also I'm getting error from the server:
{"message":"Method \"GET\" not allowed.","code":"method_not_allowed"}
What can be the reason?
I had the same issue. When redirect occurs iOS makes new request and change POST to GET. Also your body became empty.
Double check if you're by accident using http instead https.
You can also implement
(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)redirectResponse newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
but for me that wasn't solution.
Here is more details
https://developer.apple.com/forums/thread/12749?answerId=34834022#34834022
I think you can use session.uploadTask(with: request, from: uploadData).
you need to create your post string as dictionary than convert it to jason string.
if you have problem converting your data to jason tell me i ill give you a method for it.
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = yourPostDataInJASON!
print(paramString)
request.httpBody = paramString.data(using: String.Encoding.utf8)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

Http POST request in swift to send an email via Mailjet

I'm trying to send an email with the Mailjet API v3 with a http post request but I'm getting an error 400.
I used the exact same body with success in Javascript, but I guess the error 400 is related with it...
Any ideas ?
var recipients = [Any]()
recipients.append(["Email": "email#gmail.com"])
var body: [String: Any] = [
"FromEmail": "anEmail#gmail.com",
"FromName": "Me",
"Subject": "YEEES",
"Text-part": "Greetings from IOS ;)",
"Recipients": recipients
]
var request = URLRequest(url: self.apiURL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Authorization", forHTTPHeaderField: "Basic <keysInBase64>")
do {
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: [])
}
catch {
print("error during JSON serialization")
dump(error)
return
}
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
print(error)
print(response)
print(data)
})
task.resume()
Headers was wrong...
I was doing :
request.setValue("Authorization", forHTTPHeaderField: "Basic <keysInBase64>")
Instead of :
request.setValue("Basic <keysInBase64>", forHTTPHeaderField: "Authorization")
Using the Charles Proxy as suggested by #LouFranco, I was able to find the mistake.

Swift 2 JSON POST request [dictionary vs. String for HTTPBody of NSMutableURLRequest]

I have the following swift code that submits a POST request successfully.
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.HTTPBody = "foo=bar&baz=lee".dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request, completionHandler: completionHandler)
Instead of using query parameter like syntax, I'd like to use a dictionary, but when I do the following:
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(["foo":"bar", "lee":"baz"], options: [])
let task = session.dataTaskWithRequest(request, completionHandler: completionHandler)
(like what I've seen around), it seems to submits the request as if the body is empty.
My main question is: how do these syntaxes differ, and how do the resulting requests differ?
NOTE: Coming from JS, I'm testing the endpoint in a javascript environment (jquery.com's console) like the following, and it's working successfully:
$.ajax({
url: url,
method: 'POST',
data: {
foo: 'bar',
baz: 'lee'
}
});
What #mrkbxt said. It's not a matter of how the syntax differs, but a matter of the different data types your sending with your request. UTF8 string encoded text is the default value for NSMutableURLRequest content type, which is why your first request works. To use a JSON in the body you have to switch the content type to use JSON.
Add the following to your request object so it accepts JSON:
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
For a content-Type of type "x-www-form-urlencoded" you can do the following.
let bodyParameter = ["foo":"bar", "lee":"baz"]
let bodyString = bodyData.map { "\($0)=\($1)" }.joined(separator: "&")
let encodedData = NSMutableData(data: bodyString.data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.HTTPBody
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = session.dataTaskWithRequest(request, completionHandler: completionHandler)
This will take your dictionary, tranform it into a string that conforms to the content-Type of your request (by joining the dictionary using a separator) and then encoding it using utf8.

HTTP Request with Body using PATCH in Swift

I'm trying to send a Patch request with a serialized JSON Body.
For some reason the server is not able to receive the body properly. I have a feeling that there seems to be a problem with the PATCH method in combination with the http request body.
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
var URL = B2MFetcher.urlForBooking(event.unique, bookingID: booking.unique)
let request = NSMutableURLRequest(URL: URL)
request.HTTPMethod = "PATCH"
// Headers
println(token)
request.addValue(token, forHTTPHeaderField: "Authorization")
request.addValue("gzip, identity", forHTTPHeaderField: "Accept-Encoding")
// JSON Body
let bodyObject = [
"op": "cancel"
]
var jsonError: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(bodyObject, options: nil, error: &jsonError)
/* Start a new Task */
let task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
completion(data: data, response:response , error: error)
})
task.resume()
You could try to add a Content-Type header to the request:
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
or use one of the other JSON Content-Type formats described here.
I tested it with an ExpressJS server and without the Content-Type header the server got an empty body, but with a Content-Type header it worked well.
in swift 3/4 :
let request = NSMutableURLRequest(url: NSURL(string: "http://XXX/xx/xxx/xx")! as URL)
request.httpMethod = "PATCH"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
do{
let json: [String: Any] = ["status": "test"]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
request.httpBody = jsonData
print("jsonData: ", String(data: request.httpBody!, encoding: .utf8) ?? "no body data")
} catch {
print("ERROR")
}
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
completion(false)
return
}
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
completion(true)
return
}
task.resume()
Simple Way to use patch without using HTTPBody
If you want to just use patch, you just need to change the value of the name of a specific user then it will be like:
let myurl = URL(string: "https://gorest.co.in/public-api/users/"+"\(id)?"+"name=abc")!
var request = URLRequest(url:myurl)
request.addValue("Bearer yourAuthorizationToken",forHTTPHeaderField:"Authorization")
request.httpMethod = "PATCH"
let dataTask = URLSession.shared.dataTask(with: request)
dataTask.resume()
Note: here "id" will be userId

How to post a JSON with new Apple Swift Language

I'm (trying to) learn the Swift's Apple language. I'm at Playground and using Xcode 6 Beta. I'm trying to do a simple JSON Post to a local NodeJS server. I already had googled about it and the major tutorials explain how to do it in a project, not at PLAYGROUND, than don't write stupid thinks like: "google it" or "it's obvious" or "look this link" or never-tested-and-not-functional-code
This is what i'm trying:
var request = NSURLRequest(URL: NSURL(string: "http://localhost:3000"), cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 5)
var response : NSURLResponse?
var error : NSError?
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
I had tried:
var dataString = "some data"
var request = NSMutableURLRequest(URL: NSURL(string: "http://posttestserver.com/post.php"))
request.HTTPMethod = "POST"
let data = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
var requestBodyData: NSData = data
request.HTTPBody = requestBodyData
var connection = NSURLConnection(request: request, delegate: nil, startImmediately: false)
println("sending request...")
connection.start()
Thank you! :)
Nate's answer was great but I had to change the request.setvalue for it to work on my server
// create the request & response
var request = NSMutableURLRequest(URL: NSURL(string: "http://requestb.in/1ema2pl1"), cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 5)
var response: NSURLResponse?
var error: NSError?
// create some JSON data and configure the request
let jsonString = "json=[{\"str\":\"Hello\",\"num\":1},{\"str\":\"Goodbye\",\"num\":99}]"
request.HTTPBody = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// send the request
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
// look at the response
if let httpResponse = response as? NSHTTPURLResponse {
println("HTTP response: \(httpResponse.statusCode)")
} else {
println("No HTTP response")
}
It looks like you have all the right pieces, just not in quite the right order:
// create the request & response
var request = NSMutableURLRequest(URL: NSURL(string: "http://requestb.in/1ema2pl1"), cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 5)
var response: NSURLResponse?
var error: NSError?
// create some JSON data and configure the request
let jsonString = "json=[{\"str\":\"Hello\",\"num\":1},{\"str\":\"Goodbye\",\"num\":99}]"
request.HTTPBody = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
// send the request
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
// look at the response
if let httpResponse = response as? NSHTTPURLResponse {
println("HTTP response: \(httpResponse.statusCode)")
} else {
println("No HTTP response")
}
Here is a little different approach using asynchronous request. You can use synchronous approach this way too but since everyone above used synchronous request, I thought show asynchronous request instead. Another thing is it seems cleaner and easier this way.
let JSONObject: [String : AnyObject] = [
"name" : name,
"address" : address,
"phone": phoneNumber
]
if NSJSONSerialization.isValidJSONObject(JSONObject) {
var request: NSMutableURLRequest = NSMutableURLRequest()
let url = "http://tendinsights.com/user"
var err: NSError?
request.URL = NSURL(string: url)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(JSONObject, options: NSJSONWritingOptions(rawValue:0), error: &err)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) {(response, data, error) -> Void in
if error != nil {
println("error")
} else {
println(response)
}
}
}

Resources