Swift 3 URLSession sending empty request - ios

I can't get the URLSession to send anything in the body of a POST request.
Here is my code:
// Set up the request
var request = URLRequest(url: URL(string: baseURL + url)!)
request.httpMethod = "POST"
let jsonData = try JSONSerialization.data(withJSONObject: values,
options: .prettyPrinted)
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let config = URLSessionConfiguration.ephemeral
let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { data, response, err in
if let err = err {
print(err)
}
else {
let jsondata = data!
do {
let sessionData =
try JSONSerialization.jsonObject(with: jsondata, options: .mutableLeaves)
as? Dictionary<String, String>
callback.taskComplete(response: sessionData, task: task)
}
catch {
print(error)
}
}
}
task.resume()
The server receives the request, but the body is empty and the content type header is null. I can't use the default session because I'm developing with self-signed certificates, so I need my class to be a URLSession delegate.
I'm using Swift 3, XCode 8, and iOS 10. Any help would be appreciated.

Problem solved. It was a combination of errors. If the URL doesn't have the trailing "/", Jetty sends a 302 redirect to the same URL with the slash appended. The iOS client does the redirect with a "GET," so there is nothing in the body. When I add the trailing "/", the request works fine.
I hope this answer will help someone doing iOS development. I searched Google for hours before I posted this question. I finally found the answer in a post about the Apache Java HttpClient. It has the same behavior.
Thank you for all the responses.

Related

Sending a POST request in swift but getting a 405 response (method not allowed)

Im making a POST request to the API. I have tested the API using Postman and another third party tool and Im getting a 200 response. But when I make a request from swift I get a 405 response (method not allowed) and an error message saying that "GET" request is not allowed even though clearly Im making a POST request.
I have checked the httpBody which definitely contains the data. I just can't figure out what I'm doing wrong here. Here is my code:
let json : [Dictionary<String,Any>] = [["label" : "Misc", "ignored": true], ["label" : "Cash", "ignored": false]]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try? JSONSerialization.data(withJSONObject: json)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
}
}
task.resume()
Try using
URLSession(configuration: URLSessionConfiguration.default)
instead of
URLSession.shared
I ran into the same problem and this worked for me.

My url is not responding

Hi there I'm trying to make a post request so I made a class, a simple class to test the url but is not responding, I mean I can use other url different to the url that I suppose to use and It's responding so the request it's ok what is not working is the url. The weird thing is that in postman the url is working the server response ok. I also enable the app transport security allow arbitrary load to yes and still not working could you have any idea why is this? Thanks in advance.
Here is my code
#IBAction func buton(_ sender: Any) {
let parameters: [String : Any] = ["acceptPrivacyNotice": true,
"name": "xxxx xxxx",
"email":"xxx#mail.com",
"password": "qwerty2012",
"passwordConfirm": "qwerty2012",
"deviceID": "",
"isProvider": false,
"idTypeProvider":1 ]
guard let url = URL(string: "https://www.apps-sellcom-dev.com/Engie/api/account/register") else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("YOURAPIKEY==", forHTTPHeaderField: "Authorization")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print("Response",response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
}
The certificate of the domain is about to expire, so I guess thats why the URL wasn't found.
I enabled the app transport security and set the URL in the info.plist using LSApplicationQueriesSchemes, and now I'm getting a response from the server.

Making a simple HTTPS POST request with params in Swift

I cannot for the life of me figure out this problem. And I hope you guys can.
I want to send a username and a password over a HTTPS POST. Problem is, I cannot make it work.
The code I am trying to make work right now is:
import UIKit
import Foundation
import PlaygroundSupport
let url:URL = URL(string: "https://mywebsite.com/myAPI")!
let session = URLSession.shared
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "username=Pleasework&password=itwont"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
print(dataString ?? "Got nothing")
}
task.resume()
Looking at my server logs, this request goes through, but it is supposed to create a file containing said params. I tried using a Chrome extension called "Request Maker", and the file was created. (The file is created with PHP, and is irrelevant to this question)I found that the file was only created once the content type was specified, so I tried that in Swift.
I am using Swift 3 and Xcode 8, I hope you guys can help me send a simple post request with a content type to a URL, all of the other answers on Stackoverflow have not helped me.
Thanks

Making HTTP Request with header in Swift

I am trying to make an HTTP request to the Imgur API. I am trying to retrieve all images associated with the tag "cats." The url, according to the Imgur API is: https://api.imgur.com/3/gallery/t/cats
the Imgur API states the following about the authorization needed to make get requests:
For public read-only and anonymous resources, such as getting image
info, looking up user comments, etc. all you need to do is send an
authorization header with your client_id in your requests. This also
works if you'd like to upload images anonymously (without the image
being tied to an account), or if you'd like to create an anonymous
album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
I've looked at the following questions and tried things suggested there, but none of them have helped.
JSON NSURLRequest with credentials
Swift GET request with parameters
How to make a Http get and set httpHeader in Swift?
My current code is this:
let string = "https://api.imgur.com/3/gallery/t/cats"
let url = NSURL(string: string)
let request = NSMutableURLRequest(URL: url!)
request.setValue("clientIDhere", forHTTPHeaderField: "Authorization")
//request.addValue("clientIDhere", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let tache = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if let antwort = response as? NSHTTPURLResponse {
let code = antwort.statusCode
print(code)
}
}
tache.resume()
But I continually get a status code of 403, meaning authorization is required. What am I doing wrong?
I think you need to prepend Client-ID string to your actual client ID as for the header value:
request.setValue("Client-ID <your_client_id>", forHTTPHeaderField: "Authorization")
Updated for swift 4 :
func fetchPhotoRequest(YOUR_CLIENT_ID: String) {
let string = "https://photoslibrary.googleapis.com/v1/albums"
let url = NSURL(string: string)
let request = NSMutableURLRequest(url: url! as URL)
request.setValue(YOUR_CLIENT_ID, forHTTPHeaderField: "Authorization") //**
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let res = response as? HTTPURLResponse {
print("res: \(String(describing: res))")
print("Response: \(String(describing: response))")
}else{
print("Error: \(String(describing: error))")
}
}
mData.resume()
}

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

Resources