Swift POST statement returns 500 status code - ios

I'm trying to make a post call to a server and I receive a 500 status code. I've tried both sending a serialized json object and an encoded string with parameters. I don't have access to the server so I don't know if it's an issue with the server, but GET and DELETE calls work. POST and PUT don't. Here's the code:
guard let urlComponents = NSURLComponents(string: url) else
{
print("error creating URL")
return (nil, nil)
}
for (key, value) in urlParameters
{
urlComponents.queryItems = [NSURLQueryItem(name:key, value:value)]
}
let urlRequest = NSMutableURLRequest(URL: urlComponents.URL!)
urlRequest.HTTPMethod = "POST"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
do
{
let jsonUser = try NSJSONSerialization.dataWithJSONObject(["firstname": "Bob", "lastname": "Johnson", "summary": "Hi"], options: [])
urlRequest.HTTPBody = jsonUser
}
catch
{
print("Error: cannot create JSON from user")
}
let task = session.dataTaskWithRequest(urlRequest)
{
(data, response, error) in
....
I've also tried setting the httpbody like so:
let postString = "firstname=Jack&lastname=Daniels&summary=hello"
urlRequest.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
This is the server response I get:
response: <NSHTTPURLResponse: 0x7ff3137a3b70> { URL: https://somelink } { status code: 500, headers {
Connection = "keep-alive";
"Content-Length" = 1477;
"Content-Type" = "text/html; charset=utf-8";
Date = "Thu, 11 Aug 2016 00:42:52 GMT";
Server = "WEBrick/1.3.1 (Ruby/2.2.4/2015-12-16)";
Via = "1.1 vegur";
"X-Request-Id" = "4c414334-4412-48a4-a61f-c17658182bdf";
"X-Runtime" = "0.007021";
} }
Is this a problem with my POST request or the server?

It seems that the problem was the response wasn't formatted the way the server was attempting to read it. So if anyone else has this problem, double check your server (in my case I had to email someone and receive the correct format).

A 500 is an internal server error. There's no way to know from the client why it's returning that. You need to speak with someone who runs the server.
The only thing I see that you may have wrong is this:
for (key, value) in urlParameters
{
urlComponents.queryItems = [NSURLQueryItem(name:key, value:value)]
}
It should probably be this:
urlComponents.queryItems = []
for (key, value) in urlParameters
{
urlComponents.queryItems?.append(NSURLQueryItem(name:key, value:value))
}

Related

URLSession dataTask: POST request says can not connect to server, can access using POSTMAN

Probably something very silly, but scratching my head to find as to why this is happening. I have a small Flask REST server running locally on my machine and I am posting some JSON data. It's working correctly, when I check using POSTMAN, but when I invoke the POST using the following code, I get the error- Could not connect to server. What am I doing wrong, really? I checked, the URL is formed correctly.
func postJSONPayload(payload: Data, completion: ((Error?) -> Void)?) {
print("Posting JSON Payload to server........")
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "127.0.0.1"
urlComponents.port = 5000
urlComponents.path = "/mobir/api/payloads"
guard let url = urlComponents.url else {fatalError("Could not create url from components!")}
print("url is: \(url.absoluteString)")
var request = URLRequest(url: url)
request.httpMethod = "POST"
var headers = request.allHTTPHeaderFields ?? [:]
headers["Content-Type"] = "application/json"
request.allHTTPHeaderFields = headers
request.httpBody = payload
print("payload: ", String(data: request.httpBody!, encoding: .utf8) ?? "No payload in body!")
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { (responseData, response, responseError) in
print("got the response!")
guard responseError == nil else {
print("responseError not nil- error is: \(responseError!.localizedDescription)")
completion?(responseError!)
return
}
if let data = responseData, let utf8repofData =
String(data: data, encoding: .utf8) {
print("response: ", utf8repofData)
} else {
print("No data to read in response!")
}
}
task.resume()
}
OK, it was silly- answering on my own. Needed to put app.run(host= '0.0.0.0') in my Flask server code so that it's visible across the network when the URL contains the IP address of the machine. Works now.

How to log full POST request in Swift

This is trivia, but can not find good example.
I have following function for sending POST requests:
static func sendArrival(scan: ArrivalScan){
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "api.my.url.com"
urlComponents.path = "/Delivery/Arrival/?id="
guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
// Specify this request as being a POST method
var request = URLRequest(url: url)
request.httpMethod = "POST"
// Make sure that we include headers specifying that our request's HTTP body
// will be JSON encoded
var headers = request.allHTTPHeaderFields ?? [:]
headers["Content-Type"] = "application/json"
headers["ZM_APIKey"] = "mySecretKey"
request.allHTTPHeaderFields = headers
// Now let's encode out Post struct into JSON data...
let encoder = JSONEncoder()
do {
let jsonData = try encoder.encode(scan)
// ... and set our request's HTTP body
request.httpBody = jsonData
print("jsonData: ", String(data: request.httpBody!, encoding: .utf8) ?? "no body data")
} catch {
//TODO: error handling
}
// Create and run a URLSession data task with our JSON encoded POST request
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
guard responseError == nil else {
//TODO: error handling
return
}
// APIs usually respond with the data you just sent in your POST request
if let data = responseData, let utf8Representation = String(data: data, encoding: .utf8) {
print("response: ", utf8Representation)
} else {
print("no readable data received in response")
}
}
task.resume()
}
But something is not working. To decode I need to see full request (in format it will hit server). How to print this?
To see much of the information in the request printed to the console, you can use:
dump(request)
A better option in my opinion is to use a tool like Charles or Wireshark, as Rob mentions above in the comments.

POST request doesn't include params \ JSON

I've setup the api post request which is working fine with postman, however in my swift code it doesn't send the params with the request.
let parameters = ["spotId" : spotId,
"voteruptime" : currentDate,
"voterupid" : userId] as [String : Any]
guard let url = URL(string: "http://example.com:3000/upvote") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
request.httpBody = httpBody
print(request.httpBody)
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
I got a response
<NSHTTPURLResponse: 0x618000a26560> { URL: http://example.com:3000/upvote } { status code: 200, headers {
Connection = "keep-alive";
"Content-Length" = 28;
"Content-Type" = "application/json; charset=utf-8";
Date = "Sat, 21 Oct 2017 03:11:46 GMT";
Etag = "W/\"1c-BWaocQVSSeKjLiaYjOC8+MGSQnc\"";
"X-Powered-By" = Express;} }
{
n = 0;
nModified = 0;
ok = 1;
}
The server code Node JS is:
app.post('/upvote', function(req, res){
Spots.update({_id: req.query.spotId},{$push:{'upvotes':{'voterupid':req.query.voterupid,'voteruptime':req.query.voteruptime}}},function( err, Spots){
console.log(req.url)
if(err){
throw err;
}
res.json(Spots);
});
});
I tried also alamofire, and it's the same issue, no params sent to the server.
I believe the issue is that req.query accesses data passed on the query string, whereas you are POSTing the data in the body of the request.
To access the body, you need to use body-parser as described in multiple answers here: How to access the request body when POSTing using Node.js and Express?

JSON POST parsing issue in swift 3

I am trying to post data suing POST request, but whenever i am posting data I am getting Bad Request error.
Please check this code and if there any issue please let me know,
func callDataCall()
{
let requestURL: NSURL = NSURL(string: "REQUEST_URL")!
//convert MID dict to jsondata
let NewJSONData = try! JSONSerialization.data(withJSONObject: ["Disease_request":["Mid":self.MedicationID]], options: [])
// Convert jsondata to string
let NewJSONDataString = NSString(data:NewJSONData, encoding:String.Encoding.utf8.rawValue) as! String
print("Created Dictionary is : \(NewJSONDataString)")
let urlRequest = NSMutableURLRequest(url: requestURL as URL)
// set up the session
urlRequest.httpMethod = "POST"
urlRequest.httpBody = NewJSONDataString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: urlRequest as URLRequest)
{
data, response, error in
let httpResponse = response as! HTTPURLResponse
let statusCode = httpResponse.statusCode
print("status code is :\(httpResponse)")
if (statusCode == 200 || statusCode == 201)
{
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: AnyObject]
if let content = json?["Disease"] as? [[String: AnyObject]]
{
for i in 0..<content.count
{
self.medicationContent.append(content[i] as AnyObject)
}
DispatchQueue.main.async(execute: {
self.tableview_Medication.reloadData()
})
}
}
catch
{
print("Error with Json: \(error)")
}
self.stopIndicator()
}
}
task.resume()
}
Response is :
<NSHTTPURLResponse: 0x608000231e40> { URL: "REQUEST_URL" } { status code: 400, headers {
"Cache-Control" = "no-cache";
"Content-Length" = 46;
"Content-Type" = "application/json; charset=utf-8";
Date = "Wed, 30 Nov 2016 10:38:24 GMT";
Expires = "-1";
Pragma = "no-cache";
Server = "Microsoft-IIS/8.5";
"X-AspNet-Version" = "4.0.30319";
"X-Powered-By" = "ASP.NET";
"X-Powered-By-Plesk" = PleskWin;
} }
I am using the same logic for Objective C, its working fine for me.
Got the solution !!
The Swift code is fine, i need to add one more line after httpMethod
So now the code as like this
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")

error while requesting json in SWIFT + ios

I am requesting some data by json , I am new to SWIFT for iOS so I don't get whats the problem in my code :
var URL="http://X.X.X.X.X/Api/UserManagement/getMobileUser";
var UserId=uname.text;
var pword=passwd.text;
var PostData: NSString = "{\"data\":{},\"action\":\"System\",\"method\":\"getMobileUser\",\"username\":\" mpc01\",\"password\":\"mpc01\",\"type\":\"rpc\",\"tid\":\"144\"}"
let request = NSMutableURLRequest(URL: NSURL(string: URL)!)
request.HTTPMethod = "POST"
let postString = PostData
//var st:NSData = PostData.dataUsingEncoding(NSUTF8StringEncoding)!
// request.HTTPBody = PostData.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPBody = (postString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
//let data = (postString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
}
task.resume()
THE response I get is :
response = { URL: http://X.X.X.X/Api/UserManagement/getMobileUser } { status code: 500, headers {
"Cache-Control" = "no-cache";
"Content-Length" = 36;
"Content-Type" = "application/json; charset=utf-8";
Date = "Sat, 03 Jan 2015 06:11:51 GMT";
Expires = "-1";
Pragma = "no-cache";
Server = "Microsoft-IIS/7.5";
"X-AspNet-Version" = "4.0.30319";
"X-Powered-By" = "ASP.NET";
} }
responseString = Optional({"Message":"An error has occurred."})
I had a similar problem trying to POST to MailGun for some automated emails I was implementing in an app.
I was able to get this working properly with a large HTTP response. I put the full path into Keys.plist so that I can upload my code to github and broke out some of the arguments into variables so I can have them programmatically set later down the road.
// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}
if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar#foo.com"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler#<my domain>.com%3E&to=reservations#<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)
// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
The Mailgun Path is in Keys.plist as a string called mailgunAPIPath with the value:
https://API:key-<my key>#api.mailgun.net/v3/<my domain>.com/messages?
Hope this helps!

Resources