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

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)
}
}

Related

Simple post request in SwiftUI

I'm beginner in SwiftUI and I'm not familiar with variable management.
I'd like to send a very simple post request like this one with SwiftUI:
let full_path : String = "https://www.example.com/get_answer?my_message=current temperature"
I've tried with this piece of code but it didn't work.
if (URL(string: full_path) != nil) {
let url = URL(string: full_path)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
var decodedAnswer = String("")
do {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
print(response)
decodedAnswer = String(decoding: response, as: UTF8.self)
}
}
I have the following error:
Value of optional type 'URLResponse?' must be unwrapped to a value of
type 'URLResponse'
I don't know how to get the response.
How can I get the response from a simple Post request in SwiftUI?
Multiple issues here.
You are trying to decode the URLResponse object, but what you want is the data object in the decoder.
You seem to not know about optionals. I would refer you to the basic Apple tutorials about this topic. You can find it with your favorite search engine.
You are in an async context here. Everything inside the url datasession closure will be execute after your network request returns. The code in your function will be completed by that moment and your var decodedAnswer will be out of scope. So move it out of the function in to the class/struct.
You probably want something like this:
This should be defined in class scope or you won´t be able to use it:
var decodedAnswer: String = ""
This should be in a function:
let full_path: String = "https://www.example.com/get_answer?my_message=current temperature"
if let url = URL(string: full_path) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
do {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
//This converts the optionals in to non optionals that could be used further on
//Be aware this will just return when something goes wrong
guard let data = data, let response = response, error == nil else{
print("Something went wrong: error: \(error?.localizedDescription ?? "unkown error")")
return
}
print(response)
decodedAnswer = String(decoding: data, as: UTF8.self)
}
task.resume()
}
}

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.

Swift get content text response after send request to web service

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.

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 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()