Swift get content text response after send request to web service - swift

I know how to get data response from url. But the data response contains html source. Although I can handle it to get what I need but will be better if I know how to get only text. I use:
let task = URLSession.shared.dataTask(with: request)
{
data, response, error in guard
let data = data, error == nil else
{
// check for fundamental networking error
print(error!)
return
}
result = String(data: data, encoding: .utf8) ?? ""
}
task.resume()

You could do it like this.
let text = String(decoding: data, as: UTF8.self) // Convert data to string
.components(separatedBy: "\n") // Split string into multiple line
.first // Get the first line

Unless the endpoint has an option (like a query parameter) to return only the text, then you will get whatever the server wants to send and you will need to sort it out client side.

Related

URLRequest - "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value" Error (Swift)

I am trying to perform an HTTP POST request in swift that will send some data to my server using PHP file, but it crashes with the error
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
The token and selectedAreaNames (the error is in the first line) are just regular strings. What could be the problem?
let url = URL(string: "https://xxxxxxx.xxx/register.php/\(token)|\ (selectedAreaNames)")! //error is here...
var request = URLRequest(url: url)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("error: \(error)")
} else {
if let response = response as? HTTPURLResponse {
print("statusCode: \(response.statusCode)")
}
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("data: \(dataString)")
}
}
}
task.resume()
Assuming that’s really how your URL must look, you can do:
let url = URL(string: "https://xxxxxxx.xxx/register.php")!
.appendingPathComponent(token + "|" + selectedAreasNames)
That will percent escape those portions of the URL (including the |).
That having been said, this is an exceedingly unusual format for a POST request, which usually has the data being posted inside the body of the request, not just added as another path component of the URL. And if this was a GET request, where the parameters are added to the URL, you’d generally see this after a ? in the URL, separating the path of the request from the query. And this structure of simply TOKEN|VALUES is an unusual query structure, too.

error: extraneous '}' at top level in swift http post and get request

I am using an online swift playground to test http post and get request, the post aspect works fine, but when i add the get request,it gives the following error"error: extraneous '}' at top level.
The post code works fine.
// Post method
var url = URL(string: "http://196.46.20.80:8085/fideldesign")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "email=oshinowo_sola#yahoo.ca&amount=15000&description=swift&currency=566&fee=0&returnurl=http://www.oleronesoftwares.com&secretkey=2BC80A5EB5BB6A64A772F9806A7E9A0B16702043AB475DC4" // which is your parameters
request.httpBody = postString.data(using: .utf8)
//Getting response for POST Method
DispatchQueue.main.async {
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
return // check for fundamental networking error
}
// Getting values from JSON Response
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(String(describing: responseString))")
do {
let jsonResponse = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? NSDictionary
}catch _ {
print ("OOps not good JSON formatted response")
}
}
task.resume()
}
The code is to post dynamic records from user input like email address,amount,description into an external url and then return the get request in json format.
Try closing the project and opening it again.
I was getting this same error and also when I tried pressing Enter (typing newline character) on the line that was problematic (It was the last line in the file for me), Xcode would insert the characters
ker;")
into my editor.
I was getting this error, until I closed and reopened the project, in which these errors went away and the random characters stopped appearing also.
What worked for me was replacing the file.
Create new file, different name than current buggy file.
Copy/paste code into this new file.
Go ahead and delete that file with the error.
..For some reason using the same name transferred over the error, even if I deleted the other file.

How to handle 500 http errors

I am trying to access the custom server response body for 500 errors in class HTTPURLResponse (URLResponse) using URLSession.shared.dataTask function. I can only have access to statusCode and allHeaderFields but it doesn't seem to help.
The equivalent in java for ex. is HttpURLConnection.getErrorStream(), but I cannot find something similar in pure swift (I would like to solve this without using 3rd party libs).
How can I get the text response for the 500 error?
let task = session.dataTask(with: urlRequest) { data, response, error in
if let data = data, let response = response as? HTTPURLResponse {
switch response.statusCode {
case 500...599:
let yourErrorResponseString = String(data: data, encoding: .utf8)
default:
break
}
}
}
There is no way you can get the response data out of HTTPURLResponse. It only contains header information.
If you want to retrieve the response data, you need to use something like dataTask(with:completionHandler:) to send your request. That function passes (Data?, URLResponse?, Error?) to your completion handler. The data parameter of the completion handler is the data returned by the server.
For example:
import Foundation
let url = URL(string: "http://httpstat.us/500")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data, let response = response as? HTTPURLResponse else {
return
}
switch response.statusCode {
case 500...599:
print(String(data: data, encoding: .utf8) ?? "No UTF-8 response data")
default:
print("not a 500")
}
}
task.resume()
Edit: Removed force unwrap according to #Rob‘s suggestion
There is no way to get more details about a 500 error from the client side.
500 is "Internal Server Error" and it's intentionally vague and unhelpful since disclosing information about the cause of the error would assist hackers in compromising the site.
However you can get a great deal of information about the error from the server log and the log for whatever was processing your code on the server side (php, etc.).
If you have access to the server logs and don't see enough information, you can increase the level of logging for the server and application.

How to Call HTTP Get and Save in Variable In Swift?

My question is simple: how do you call a HTTP GET Request in Swift?
I am trying to retrieve specific data from server (I have the URL string), the problem is that the previous answers I saw, doesn't explain thoroughly how to request an HTTP Get and save the retrieved information in a variable to be used later? Thanks in advance!
Here's what I have so far:
let myURL = NSURL(string:"https://api.thingspeak.com/channels/CHANNEL_ID/last_entry
_id.txt");
let request = NSMutableURLRequest(url:myURL! as URL);
request.httpMethod = "GET"
Not sure what do following requesting the GET.
In your post you are missing the part that does the actual getting to of the data.
Your code should look something like this to get the value out of the text file.
var lastID: String?
let myURL = NSURL(string:"https://api.thingspeak.com/channels/1417/last_entry_id.txt");
let request = NSMutableURLRequest(url:myURL! as URL);
//request.httpMethod = "GET" // This line is not need
// Excute HTTP Request
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
// Check for error
if error != nil
{
print("error=\(error)")
return
}
// Print out response string
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString!)")
lastID = "\(responseString!)" // Sets some variable or text field. Not that its unwrapped because its an optional.
}
task.resume()

Sending simple POST in Swift, getting "Empty Post" response

I have registration page in my iOS app that I'm trying to write in Swift. The first thing I'm testing out is sending a POST with the email address, this is the way I'm doing so:
var bodyData = ("userEmail=%#\" \" &userPassword=%#\" \"&userDevice=%#\" \"", emailAddress.text, password.text, deviceModel)
let dataToSend = (bodyData as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPMethod = "POST"
request.HTTPBody = dataToSend
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
// print("response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
However, I'm getting a message back stating that it was an empty post. This is the exact response from the output above: responseString = Optional({"complete":"false","message":"Empty Post"})
I've researched different ways to send a simple POST in Swift, and this appears to be correct. I can't see anything wrong with it or why it would output a message saying that the post was empty... Except for maybe the format of the string?
The database is expecting multiple things for the "new user" service, and I'm only sending one part due to it being a test. Could this be the issue? The new-user service is expecting:
Service URL : https://test.com/services/new-user/
Required Post Fields:
For New User:
'userEmail'
'userPassword'
'userDevice'
(From the documentation).
I haven't worked with web services much. After brainstorming more I think these may be the culprits: I may be getting the response back because I'm not sending all the data at once. I also may be sending it incorrectly. Can I send it as text or do I need to send it as JSON?
A couple of issues:
You have a line that says:
var bodyData = ("userEmail=%#\" \" &userPassword=%#\" \"&userDevice=%#\" \"", emailAddress.text, password.text, deviceModel)
That does not do what you intended. It's creating a tuple with four items that consists of a format string and three values, not a single formatted string. Print the bodyData and you'll see what I mean.
You either want to use String(format: ...), or even easier, use string interpolation. (See code snippet below.)
Assuming that emailAddress and password are UITextField objects, note that the text property is optional, so you have to unwrap those optionals before you use them. Look at the bodyData string and you'll see what I mean.
I don't know if deviceModel was optional as well, but if so, unwrap that, too.
You have a space right before the userPassword parameter of the request. That will make it not well formed. Remove that space. You can probably simplify that format string by getting rid of a bunch of those \" references, too.
You probably should be specifying the Content-Type of the request. It's often not necessary, but it's good practice.
You're clearly getting a JSON response, so you might want to parse it.
Thus, you might do something like:
guard emailAddress.text != nil && password.text != nil else {
print("please fill in both email address and password")
return
}
// use
//
// let bodyString = String(format: "userEmail=%#&userPassword=%#&userDevice=%#", emailAddress.text!, password.text!, deviceModel)
//
// or use string interpolation, like below:
let bodyString = "userEmail=\(emailAddress.text!)&userPassword=\(password.text!)&userDevice=\(deviceModel)"
let bodyData = bodyString.dataUsingEncoding(NSUTF8StringEncoding)
request.HTTPMethod = "POST"
request.HTTPBody = bodyData
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
guard error == nil && data != nil else {
print("error=\(error)")
return
}
do {
let responseObject = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(responseObject)
} catch let parseError as NSError {
print(parseError)
}
}
task.resume()
Note, you really should be percent-escaping the values you are adding to the body, too (notably, if the values might have spaces, +, &, or other reserved characters in them). See https://stackoverflow.com/a/28027627/1271826.
If you don't want to get into the weeds of this sort of stuff, consider using a framework like Alamofire, which takes care of this stuff for you. For example:
guard emailAddress.text != nil && password.text != nil else {
print("please fill in both email address and password")
return
}
let parameters = [
"userEmail" : emailAddress.text!,
"userPassword" : password.text!,
"userDevice" : deviceModel
]
Alamofire.request(.POST, urlString, parameters: parameters)
.responseJSON { response in
switch response.result {
case .Failure(let error):
print(error)
case .Success(let value):
print(value)
}
}