JSONSerialization swift response is always nil - swift

I'm performing a post request over my rest api that I built in node. Then the data are stored in a mongodb collection.
This is my code that I use to post the request:
// create dataTask using the session object to send data to the server
let task = session.dataTask(with: request) { data, response, error in
if let error = error {
print("Post Request Error: \(error.localizedDescription)")
return
}
// ensure there is valid response code returned from this HTTP response
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode)
else {
print("Invalid Response received from the server")
return
}
// ensure there is data returned
guard let responseData = data else {
print("nil Data received from the server")
return
}
do {
// create json object from data or use JSONDecoder to convert to Model stuct
if let jsonResponse = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers) as? [String: ErrorHandler] {
print(jsonResponse)
DispatchQueue.main.async {
self?.isLoading = false
self?.signedIn = true
}
} else {
print("data maybe corrupted or in wrong format")
throw URLError(.badServerResponse)
}
} catch let error {
print(error.localizedDescription)
}
}
task.resume()
The problem is that the responseJson is always nil. I tried to perform the same request with postman and I get the response correctly. What is the problem? Also because the data are correctly uploaded everywhere.
This is my postman result of the same post request.

Related

URLSession with URLCredential

I would like to get data from server, but credential (username, password. Not Basi Authentification) is necessary to get it. Therefore, I try to use URLSession with URLCredential as following:
https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge
However, I could not understand this document...
So could you tell me how to use URLSession with URLCredential?
I tried URLSession like:
func startLoad() {
let url = URL(string: "https://www.abcde-test-url.com/")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("client error: \(error.localizedDescription) \n")
return
}
guard let data = data, let response = response as? HTTPURLResponse else {
print("no data or no response")
return
}
if response.statusCode == 200 {
print(data)
} else {
print("error status code: \(response.statusCode)\n")
}
}
task.resume()
}
But I couldn't understand the usage with URLCredential.

Passing JSON Decode error into something actionable

I'm trying to improve my error handling when I don't get back any data in my JSON. The function below works fine without any issues except if I catch an error. I'm not sure of how to pass the error to prompt the user or is the way to handle the error if googlebusinessinfo is nil I likely have no data and pass a generic error?
Here's my function:
func getBusinessReviews(googleUrl: String, completion: #escaping (WelcomeReview?) -> ()) {
// Create URL
let url = URL(string: googleUrl)
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Specify HTTP Method to use
request.httpMethod = "GET"
//Set HTTP Header
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Specify HTTP Method to use
request.httpMethod = "GET"
print("(Google)Do we have any data: \(String(describing: data))")
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("(Google)Response HTTP Status code: \(response.statusCode)")
}
// Convert HTTP Response Data to a simple String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Googledata Response data string:\n \(dataString)")
}
if let googlebusinessdata = data {
do {
let googlebusinessinfo = try JSONDecoder().decode(WelcomeReview.self, from: googlebusinessdata)
print("googledata \(googlebusinessinfo)")
completion(googlebusinessinfo)
} catch
{
print("googledata error \(error.localizedDescription)")
let googebusinessinfoerror = error.localizedDescription
}
}
}
task.resume()
}
First of all you can improve the error handling immensely if you print error instead of error.localizedDescription in a Decoding catch block. The former shows the real error, the latter a meaningless generic message.
To answer your question use the generic Result type
func getBusinessReviews(googleUrl: String, completion: #escaping (Result<WelcomeReview,Error>) -> ()) {
// Create URL
let url = URL(string: googleUrl)
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Specify HTTP Method to use
request.httpMethod = "GET"
//Set HTTP Header
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Specify HTTP Method to use
request.httpMethod = "GET"
print("(Google)Do we have any data: \(String(describing: data))")
// Check if Error took place
if let error = error {
print("Error took place \(error)")
completion(.failure(error))
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("(Google)Response HTTP Status code: \(response.statusCode)")
}
// Convert HTTP Response Data to a simple String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Googledata Response data string:\n \(dataString)")
do {
let googlebusinessinfo = try JSONDecoder().decode(WelcomeReview.self, from: data)
print("googledata \(googlebusinessinfo)")
completion(.success(googlebusinessinfo))
} catch
{
print("googledata error:", error)
let googebusinessinfoerror = error.localizedDescription
completion(.failure(error))
}
}
}
task.resume()
}
and call it
getBusinessReviews(googleUrl: "Foo") { result in
switch result {
case .success(let info): print(info)
case .failure(let error): print(error)
}
}

unable to have a result while calling a rest API with Swift

I try to make a small command line program in swift 5 to call a Rest Web service
func callRest() {
URLCache.shared = URLCache(memoryCapacity: 0, diskCapacity: 0, diskPath: nil)
let todoEndpoint: String = "http://myURL"
print (todoEndpoint)
guard let url = URL(string: todoEndpoint) else {
print("Error: cannot create URL")
exit(1)
}
// private let apiKey = "my API Key"
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
"Accept": "application/json",
"API-Key": "my API Key"
]
var session = URLSession.shared
session = URLSession(configuration: config)
let urlRequest = URLRequest(url: url)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
print ("task")
// check for any errors
guard error == nil else {
print("error calling GET on /todos/1")
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
// check the status code
guard let httpResponse = response as? HTTPURLResponse else {
print("Error: It's not a HTTP URL response")
return
}
print (httpResponse)
}
task.resume()
// Response status
}
print ("debut")
callRest()
print("fin")
And I never see a result...
the line print ("task") is never display
Any help appreciate.
I think I don't really understand the task.resume usage...
(same code work in a playground)

Error in POST Request in swift

I wanted to be a type of variable to send to the dictionary server but But on the line I was faced with the problem let task = session.dataTaskWithRequest(todosUrlRequest) error : Cannot convert value of type 'NSURL' to expected argument type 'NSURLRequest'
I had two questions
1) What is this error?
2)Is there a procedure that I used for POST is that right? doesn't need anything else. ??
thank you for help
func data_request (){
let url = "http://sample.com/api/Flight/GetTicketInformation"
guard let todosUrlRequest = NSURL(string: url) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL: todosUrlRequest)
request.HTTPMethod = "POST"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let newTodo = ["Roundtrip": roundTrip,
"OneWay": oneWay,
"MultiWay": multiWay,
"Adult": numberAdults,
"Child": numberchild,
"Baby": numberinfant,
"SourceCityId": cityIDOrigin,
"DestinationCityId": cityIDPurpose,
"DepartingDate": raftDate,
"ReturningDate": bargashtDate ]
let jsonTodo: NSData
do {
jsonTodo = try NSJSONSerialization.dataWithJSONObject(newTodo, options: [])
request.HTTPBody = jsonTodo
} catch {
print("Error: cannot create JSON from todo")
return
}
request.HTTPBody = jsonTodo
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(todosUrlRequest) {
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("error calling POST on /todos/1")
print(error)
return
}
// parse the result as JSON, since that's what the API provides
do {
guard let receivedTodo = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as? [String: AnyObject] else {
print("Could not get JSON from responseData as dictionary")
return
}
print("The todo is: " + receivedTodo.description)
} catch {
print("error parsing response from POST on /todos")
return
}
}
task.resume()
}
request instead of todosUrlRequest on the line let task = session.dataTaskWithRequest(todosUrlRequest)
for the second question, no idea . sorry
I can recommend you Alamofire for all requests, instead of writing all code on your own.
https://github.com/Alamofire/Alamofire

dataTaskWithURL sometimes no return

I have a very simple http request which will return a JSON data. Here is my code:
let query = NSString(format: "http://glosbe.com/gapi/translate?from=eng&dest=eng&format=json&phrase=test",src, dest, phrase )
let url = NSURL(string: query)
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) in
if let httpRes = response as? NSHTTPURLResponse {
println("status code=",httpRes.statusCode)
if httpRes.statusCode == 200 {
println(NSString(data: data, encoding: NSUTF8StringEncoding))
// parse data
let phrase = Phrase.parse(data)
println(phrase.description)
}
}
}
task.resume()
Sometimes the completionHandler isn't called at all. I suspect it's the problem of the server. But when I input the same url into my browser and tried a dozens times. There was no problem at all. The data was returned everything when I refresh the browser.
Is there anything wrong in my code? Thanks
The code works OK for me. I suggest you can make this change to your code (an else clause):
if let httpRes = response as? NSHTTPURLResponse {
println("status code=",httpRes.statusCode)
if httpRes.statusCode == 200 {
println(NSString(data: data, encoding: NSUTF8StringEncoding))
// parse data
let phrase = Phrase.parse(data)
println(phrase.description)
}
} else {
println("error \(error)") // print the error!
}
So you will have a better idea if anything goes wrong