I have a simple string in swift:
let str = "{"phone": "+79217463536","name": "skjfhkjdhg","username": "ksfhksdjhf"}"
I generate Data:
let data = str.data(.utf8)
and then send data to request.httpBody = data, and then send post request.
When swift transforms string to data, it adds a character "\", and server dont understand my json.
"{\"phone\": \"+79217463536\",\"name\": \"skjfhkjdhg\",\"username\": \"ksfhksdjhf\"}"
In python it work good.
Help me please, I need to transform string to data without any symbols, or I need to send request without data, and with string.
Don´t create the data this way, it is error prone. And there is a better way.
Create a struct that holds your data:
struct Model: Codable{
let name: String
let phone: String
let username: String
}
Instantiate the model with appropriate values:
let model = Model(name: "name here", phone: "phone here", username: "username here")
Create the data from this model:
let data = try JSONEncoder().encode(model)
Then send this data via the URLRequest.
And you should add the contenttype header. Else your api won´t understand what your are sending.
let url = URL(string: "plannerok.ru/api/v1/users/register/")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = data
// add this
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
Related
I've got simple struct:
struct LoginModel: Codable {
var user: String
var password: String
}
Fill my model and encode using JSONEncoder().
Next create URLRequest
let request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: timeOut)
let headers = [
"Content-Type": "application/json",
"cache-control": "no-cache",
]
request.allHTTPHeaderFields = headers
request.httpMethod = "POST"
request.httpBody = data
run URLSessionDataTask with this request from URLSession.shared.
Beckend gets json with null fields.
But instead I've sent dictionary with fixed filed it's work fine.
let parameters = [
"user": "user",
"password": "hash"
]
let data = JSONSerialization.data(withJSONObject: parameters, options: [])
When I decode using JSONDecoder() back to my model, all variable are filled.
Server side endpoints using other apps written in objc. This app using NSDicionary and NSJSONSerialization and work fine.
How to pass JSON data dynamically.
I have a Vapor API that has a route to register users. This route recibes a nested object in JSON format like this:
{
"name": "Test",
"email": "test1#test.com",
"password": "Test1",
"phone": {
"numberString": "+52 999 999 9999",
"countryCode": 52,
"nationalNumber": 9999999999,
}
}
This JSON is converted into a Content/Codable Object:
final class Create: Codable, Content {
let name: String!
let email: String!
let password: String
let phone: PhoneNumber!
init(name: String, email: String, password: String, phone: PhoneNumber) {
self.name = name
self.email = email
self.password = password
self.phone = phone
}
}
I have tried this route sending the JSON string as raw via Postman and the route worked perfectly but the problem is when I try to send it via URLSession in my iOS counterpart the ErrorMiddleware throws a DecodingError:
DecodingError: Value of type 'String' required for key 'password'.
At first I thought that the problem was the JSON generation until, for test purpose I send the same JSON as in the example and the Vapor API is still throwing the Error.
let urlStr = "\(BaseURL)/api/student/register"
guard let url = URL(string: urlStr) else { return }
var urlRequest = URLRequest(url: url, cachePolicy:
.reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30.0)
let raw = "{\"name\":\"Prueba\",\"email\":\"prueba1#hotmail.com\",\"password\":\"Prueba1\",\"phone\":{\"numberString\":\"\",\"countryCode\":,\"nationalNumber\":}}"
urlRequest.httpMethod = "POST"
urlRequest.httpBody = raw.data(using: .utf8)
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
...
}.resume()
Can you even send this types of JSON's via URLSession or do I need to change my logic so it will receive a flat array?
After hours of debugging and getting strange errors I realized that my error was simpler than I thought.
The error was:
{"error":true, "reason":"Value of type 'String' required for key 'password'."}
And I tried to send in Postman a request with out the key 'password' which returned:
{"error": true, "reason": "Value required for key 'password'."}
What got me to analyze my objects and then I saw the error, my Create object wasn't unwrapped correctly, more precisely this:
let password: String
Should be having a ! next to String like this.
let password: String!
The reason why this worked on Postman and not on URLSession is still uncleared.
UPDATE:
As proposed by #vadian the headers in this URLSession are also missing and even tho after I added the force unwrapped the API passed the request but with nil content
urlRequest.setValue("application/json", forHTTPHeaderField:"Accept")
urlRequest.setValue("application/json", forHTTPHeaderField:"Content-Type")
Set also the content-type and length header
urlRequest.setValue(String(Data(json.utf8).count), forHTTPHeaderField:"Content-Length")
urlRequest.setValue("application/json", forHTTPHeaderField:"Accept")
urlRequest.setValue("application/json", forHTTPHeaderField:"Content-Type")
And never, never, never declare properties in a class as implicit unwrapped optional which are initialized with non-optional values.
I am using two textfields to pass login information to the PHP web service using Alamofire in the following way.
#IBAction func LoginButton(_ sender: Any) {
//getting the username and password
let parameters: Parameters=[
"Name":TextFieldUserName.text!,
"Pass":TextFieldPassword.text!
]
Alamofire.request(URL_USER_LOGIN, method: .post, parameters: parameters).responseJSON
{
response in
//printing response
print(response)
The following Json data is received on login.
[{"code":0,"message":"Check Username and Password....","userid":""}]
I want to use either "code" value (0 for false and 1 for true) or "message" value as String to put into an if - else statement for further steps. If Alamofire is not the best way to go about this, can someone please show another way. Thanks in advance for the help.
Do you need to deserialize the response from the server?
The easiest option is parsing response value as NSDictionary
if let JSON = response.result.value as? NSDictionary {
let code = JSON.value(forKey: "code") as? Int
let message = JSON.value(forKey: "message") as? String
}
You can also use the Codable protocol and the JSONDecoder to decode this response into your structure.
For example, declare struct:
struct LoginResponse: Codable {
var code: Int
var message: String
}
and decode response using JSONDecoder
let jsonDecoder = JSONDecoder()
let loginResponse = try? jsonDecoder.decode(LoginResponse.self, from: response.data)
I am trying to learn JSON parsing. I have written an API in Laravel, which returns status : 200 in response. What I did is this:
guard let url = URL(string: "http://localhost/workon-api/public/api/register") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let newUser = User.init(name: "Rob", email: "abc#gmail.com", password: "12345678")
do {
let jsonBody = try JSONEncoder().encode(newUser)
request.httpBody = jsonBody
} catch { }
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let json = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
print(json)
} catch {}
}.resume()
Now, I am getting this error: Invalid top-level type in JSON write and app's crashing. After searching, I used this:
let json = try JSONSerialization.jsonObject(with: data, options: [])
And, it works. Why the previous method is not working? And, I get a response like this if I try to return the collected userInfo.
status = "{\"name\":\"Rob\",\"email\":\"abc#gmail.com\",\"password\":\"12345678\"}";
Why are back-slashes there? Are these okay? And, what is Gzip data? I know I am asking a lot, but I need to understand this. Thanks in advance.
P.S. : Here is the User Model.
struct User: Encodable {
let name : String?
let email : String?
let password : String?
}
First of all the backslashes are virtual. The framework adds them to be able to print double quotes within a literal string.
Secondly dataTask returns serialized JSON Data so to get a dictionary or array from the data you have to call jsonObject(with.
let object = try JSONSerialization.jsonObject(with: data)
print(object)
Im sending a Post message to my database with swift. But how do i handle the data from that response? My variable responseString looks like this now. I want to get each parameter and work with them.
Optional([{"id":"9","name":"hallow","strasse":"street","tel_nr":"123456789","kommentar":"comment"}])
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost/getByName.php")!)
request.HTTPMethod = "POST"
let postString = "name=hallow"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
Your php is returning an array containing a dictionary, so you'd have to access it like
if let responsedict = response.first {
print(responsedict["id"])
}// prints 9
(if you know there's going to be no other elements returned first is ok...or change how your data is sent back).
You could take it one step further and parse the response in to a model e.g.
let person = Person(id: response.first?["id"], name: response.first?["name"], etc)
print("id \(person.id)")
//id 9