Swift trouble send request with dynamic field json - json

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.

Related

swift JSONEncoder generate not valid data

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

Encoding JSON body properly in Swift for HTTP Request

I am trying to encode key/value pairs in JSON for an HTTP request in Swift on iOS 15, but everything I try to put in the body shows up as the key when I post it.
The code:
var request = URLRequest(url: url)
let body = [
"email": "abc#gmail.com",
"password": "123456"
]
let bodyData = try? JSONSerialization.data(
withJSONObject: body, options: []
)
request.httpMethod = "POST"
request.httpBody = bodyData
When I post this to the server, the server receives:
{
"{\"email\":\"abc#gmail.com\",\"password\":\"123456\"}": ""
}
Am a Swift beginner, many thanks for any responses to this...
Try adding this to the request
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
That is what solved it for me when I had the same problem. This tells the server to parse the json as json instead of
{ jsonBody : "" }
which is what it seems to be doing right now.

Alamofire POST not working as expected. Error on parameters

I am trying to upload (post) a JSON string using Alamofire and I'm getting an error that leads me to believe there is some issue in the dictionary encoding.
The array I am encoding is an array of objects, all of type String. It looks like this:
class SavedDeliveries: Codable { //not sure if this is the issue (I use this to store default values locally)
var fullName = ""
var address = ""
var city = ""
var zip = ""
var phone = ""
var orders = ""
var ordersListed = ""
var pickup = ""
}
The code including the Alamofire call looks like this:
func postData() {
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx", //API Key
"X-Bin-Name": "deliverydata"]
let jsonEncoder = JSONEncoder()
let jsonData = try! jsonEncoder.encode(deliveryList)
let json = String(data: jsonData, encoding: String.Encoding.utf8)
print(json!) // printing the JSON and it is correct when validated.
AF.request("https://api.jsonbin.io/v3/b", method: .post, parameters: json, encoding: JSONEncoding.default, headers: headers).responseString { (response) in
switch response.result {
case .success:
print("was successful")
case let .failure(error):
print(error)
}
}
}
I expect it to upload the JSON file but I'm getting an error message that says this:
Cannot convert value of type 'String?' to expected argument type 'Parameters?' (aka 'Optional<Dictionary<String, Any>>')
Not sure if the AF call parameter is expecting a certain kind of dictionary key:value format. If this is not the right call format for uploading JSON, what do I need to change?
Thanks for any help. I'm not a full-time Swift developer but manage an app that is usually within my capabilities. This one has me stumped.
I guess I don't understand much about HTTP requests or Alamofire, but I was able to solve this issue with the following mods to my code (without Alamofire, which seems like overkill in this case).
func postData() {
// Prepare URL
let url = URL(string: "https://api.jsonbin.io/v3/b")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Body
let header: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx",
"X-Bin-Name": "deliverydata"
]
request.headers = header
let jsonEncoder = JSONEncoder()
let jsonData = try! jsonEncoder.encode(deliveryList)
let json = String(data: jsonData, encoding: String.Encoding.utf8)
request.httpBody = json!.data(using: String.Encoding.utf8)
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check for Error
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a String
if let data = data, let dataString = String(data: data, encoding: .utf8) {
print("Response data string:\n \(dataString)")
}
}
task.resume()
}
To make such a request using Alamofire, I'd recommend:
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"X-Master-Key": "xxx", //API Key
"X-Bin-Name": "deliverydata"]
AF.request("https://api.jsonbin.io/v3/b",
method: .post,
parameters: deliveryList,
headers: headers).responseString { response in
switch response.result {
case .success:
print("was successful")
case let .failure(error):
print(error)
}
}
Even better, create a Decodable response type and use responseDecodable to parse it.
I would also suggest not using empty strings as your default values, that can easily lead to sending bad or invalid data to the backend.

How to send multiple JSON objects as a stream using alamofire

I want to send multiple different JSON object in a single request, i felt streaming the multiple JSON objects like a file in a single request would be better, so kindly let me know if it is possible, if so kindly give me an idea of how to do it using Alamofire, Below is the formate of the raw body (application/json) data that i want to post
{"a":23214,"b":54674,"c":"aa12234","d":4634}
{"a":32214,"b":324674,"c":"as344234","d":23434}
{"a":567214,"b":89674,"c":"sdf54234","d"34634}
I tried the below code, but it didn't work as the body param is not in the correct format, that's the reason i want to try sending the multiple JSON objects as a stream in a single request, Kindly advice
let SendParams = [
["a":1234, "b":2345, "c":3456], ["a":2345, "b":3456, "c":4567], ["a":3456, "b":4567, "c":5678]
]
_ = Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding, headers: header)
JSON format is not correct for your request, JSON is always key-value pair, where key is always String, and value is any Object. In your example need to set key at top level for object of type Array as below:
let SendParams = [
"key" :[["a":1234, "b":2345, "c":3456], ["a":2345, "b":3456, "c":4567], ["a":3456, "b":4567, "c":5678]]
]
_ = Alamofire.request(url, method: .post, parameters: SendParams, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in}
OR
Serialise the array and set as httpBody of URLRequest object:
let url = YOUR_POST_API_URL
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let values = [
["a":1234, "b":2345, "c":3456], ["a":2345, "b":3456, "c":4567], ["a":3456, "b":4567, "c":5678]
]
request.httpBody = try! JSONSerialization.data(withJSONObject: values)
Alamofire.request(request)
.responseJSON { response in
// do whatever you want here
switch response.result {
case .failure(let error):
print(error)
if let data = response.data, let responseString = String(data: data, encoding: .utf8) {
print(responseString)
}
case .success(let responseObject):
print(responseObject)
}
}

How to create a particular data structure in swift . Swifty Json not useful :(

i'm porting my really simple app from javascript (embedded in an app) to ios8/swift and Xcode.
The app will insert some simple event in google calendar using CalendarApiV3.
In javascript it was easy to create a simple data structure to pass in a http POST request, like this structure :
var data:struct =
{
"end": {
"dateTime": "20141223T12:25:00Z"
},
"start": {
"dateTime": "20141223T10:25:00Z"
},
"summary": "description of event",
"reminders": {
"useDefault": false,
"overrides": [
{
"method": "sms",
"minutes": "60"
},
{
"method": "email",
"minutes": "60"
}
]
}
};
Ok, how to re-create the some structure in Swift ?
I ended up looking for swifty json, but they all tell me how to PARSE json requested, not how to FORM a json request.
I hope i was clear.
Thanks in advance.
Victor
Here's a very simple example and I assume that nobody wants to deal with JSON strings, they want to have them created from data structures.
var dict1 = ["dave": "drangle", "hume": "cronyn"]
var dict2 = ["bob": "fossil", "vince": "powers"]
var ary = [dict1, dict2]
var jsonData = JSON(ary)
var post:NSData = jsonData.rawData()!;
var postLength:NSString = String(post.length)
var url:NSURL = NSURL(string: "https://some.server.com/mobile.php")!
var request:NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = post
request.setValue(postLength, forHTTPHeaderField: "Content-Length")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
if let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil) {
println(data)
}
As you can see, it's an array of dictionaries which then gets converted to a SwiftyJSON struct. The jsonData.rawData()! is what gets you NSData which is the required datatype for request.HTTPBody. Here's what you see on the PHP server side of things using file_get_contents("php://input") and print_r(json_decode()):
[{"hume":"cronyn","dave":"drangle"},{"bob":"fossil","vince":"powers"}]
Array
(
[0] => stdClass Object
(
[hume] => cronyn
[dave] => dangler
)
[1] => stdClass Object
(
[bob] => fossil
[vince] => powers
)
)
SwiftyJSON is great for building JSON object from AnyObject in swift.
You can take a look at the site about how to create JSON object from AnyObject.
After you have your own JSON object, the site actually mentioned about how to creating JSON string you can use in HTTP Request.
if let string = json.rawString() {
//Do HTTP Request here
}
here cezar answered greatly about how to use HTTP Request in swift : How to make an HTTP request in Swift?
Update:
So I assume that you have jsonString available, you can use this to make your swiftyJSON object
let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let jsonObject = JSON(data: data!)