I usually use this code to parse most of JSON responses
Before the code, here the JSON I need to get form it the "workspace"
{
"count": 1,
"next": null,
"previous": null,
"results": [{
"id": 307,
"email": "999#ios.net",
"firstName": "fighter",
"categories": [],
"workspace": 302,
"phone": "25485"
}]
}
here is my code:
func getWorkSpace() {
DispatchQueue.main.async {
let returnAccessToken: String? = UserDefaults.standard.object(forKey: "accessToken") as? String
print("UserDefaults Returned Access Token is: \(returnAccessToken!)")
let access = returnAccessToken!
let headers = [
"content-type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"postman-token": "dded3e97-77a5-5632-93b7-dec77d26ba99",
"Authorization": "JWT \(access)"
]
let request = NSMutableURLRequest(url: NSURL(string: "https://v5/workspaces/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error!)
} else {
if let dataNew = data, let responseString = String(data: dataNew, encoding: .utf8) {
print("--------")
print(responseString)
print("--------")
DispatchQueue.main.async {
do {
let json = try JSON(data: data!, options: .allowFragments)
let answer = json["results"]
let workspace = Int(answer["workspace"].int!)
// let workspace = Int(answer["workspace"].string!)!
// let workspace = answer["workspace"].int!
print("Workspace is: \(workspace)")
} catch {
print("Error saving workspace!")
}
}
}
}
})
dataTask.resume()
}
}
This code usually works for me, but this time it's not. Please don't suggest me to use Codables because I didn't learn them yet.
SwiftyJSON
do {
let json = try JSON(data: data1!)
let answer = json["results"].array
answer?.forEach {
print($0["workspace"].int!)
}
} catch {
print("Error saving workspace!")
}
JSONSerialization
let json = try! JSONSerialization.jsonObject(with:data, options :[]) as! [String:Any]
let results = json["results"] as! [[String:Any]]
results.forEach {
print($0["workspace"] as! Int)
}
Codable
struct Root : Codable {
let results:[Model]
}
struct Model: Codable {
let id: Int
let email, firstName: String
let workspace: Int
let phone: String
}
let res = try! JSONDecoder().decode(Root.self, from:data)
print(res.results)
Related
I am able to make a successful POST request in POSTMAN like this:
{
"id": "1",
"myDictKey": {
"key0": "blah",
"key1": "blah",
"key2": "blah"
}
}
However, when I try to make this POST request in swift, the POST is unsuccessful. The NSDictionary param doesn't seem to get encoded as expected.
Swift Code
let dictParam = ["key0": "blah", "key1": "blah", "key2": "blah"] as NSDictionary
let urlString = MY_URL
let url = URL(string: urlString)!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let parameters: [String: Any] = [
"id": "1",
"myDictKey": dictParam
]
request.httpBody = parameters.percentEncoded()
let task = URLSession.shared.dataTask(with: request) { data, response, error -> Void in
if error != nil {
completion(nil, error?.localizedDescription)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: [.allowFragments]) as? NSDictionary {
if response?.statusCode() == 200 {
if let jsonResponse = json.value(forKeyPath: "response") as? NSDictionary {
completion(jsonResponse, nil)
return
} else if response?.statusCode() == 401 {
completion(nil, "Unauthorized")
} else {
completion(nil, "Something went wrong. Try again later")
}
}
} catch {
completion(nil, "Something went wrong. Try again later")
}
}
task.resume()
percentEncoded()
// MARK: - Dictionary
extension Dictionary {
func percentEncoded() -> Data? {
return map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
}
CharacterSet
// MARK: - CharacterSet
extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]#" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}
What you need is to JSONSerialize the parameter:
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
You can create Encodable model for your request body.
Something like this:
struct MyRequestBodyModel: Encodable {
let id: String
let myDictKey: MyNestedModel
}
struct MyNestedModel: Encodable {
let key0: String
let key1: String
let key2: String
}
And after:
do {
let requestBody = MyRequestBodyModel(...)
request.httpBody = try JSONEncoder().encode(requestBody)
} catch {
// Handle error here
}
I think this way is clearer and easier to maintain.
I am starting my adventure with Swift and iOS developing. And I am fighting for few hours with parsing this json result:
[
[
{
"id": 289462,
"value": "24.80",
"taken_at": "2017-07-02 19:03:03",
"key": "temperature"
}
],
[
{
"id": 289463,
"value": "52.20",
"taken_at": "2017-07-02 19:03:05",
"key": "humidity"
}
]
]
It hasn't got this "name" before all of results, and I don't know, maybe this is causing errors? And below is my function to get data:
func get_data()
{
let headers = [
"content-type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"postman-token": "fd20c3c4-650e-743c-3066-597de91f3873"
]
let postData = NSMutableData(data: "auth_key=32fd26f62677e7aa56027d9c228e1e9d6d96abc5d10f547dcb66e2a2f6ed13".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://192.168.0.22/last")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
// print(error)
} else {
//let httpResponse = response as? HTTPURLResponse
var keys = [String]()
do {
if let data = data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let mes = json[""] as? [[String: Any]] {
for me in mes {
if let name = me["key"] as? String {
keys.append(name)
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}
print(keys)
}
})
dataTask.resume()
}
I've tried several codes from different sites which I googled and still array is remaining empty :(
You're right the JSON is strange, the root object is [[Any]]. You can get the key values with
if let json = try JSONSerialization.jsonObject(with: data) as? [[Any]] {
for item in json {
if let firstItem = item.first as? [String:Any], let key = firstItem["key"] as? String {
keys.append(key)
}
}
}
However if the JSON was in much more suitable format
[
{
"id": 289462,
"value": "24.80",
"taken_at": "2017-07-02 19:03:03",
"key": "temperature"
},
{
"id": 289463,
"value": "52.20",
"taken_at": "2017-07-02 19:03:05",
"key": "humidity"
}
]
you could reduce the code to
if let json = try JSONSerialization.jsonObject(with: data) as? [[String:Any]] {
keys = json.flatMap { $0["key"] as? String }
}
I want to send following object as body parameter. But serialization is failing:
{
"StartAddress":"Colombo",
"EndAddress":"Kandy",
"DepartureAddress":"Kollupitiya, Colombo",
"ArrivalAddress":"Peradeniya, Kandy",
"CreatedDate":"2017-07-30",
"Date":"2017-07-30",
"Time":"2017-07-30",
"IsLadiesOnly":true,
"IpAddress":"fe80::8638:38ff:fec8:ea50%wlan0",
"Country":"Srilanka",
"VehicleId":"1129",
"StartLocation":[
6.9270974,
79.8607731
],
"EndLocation":[
7.2916216,
80.6341326
],
"Points":"k}gi#y{lf",
"Route":{
"Bounds":{
"NorthEast":[
7.2916216,
80.6341326
],
"SouthWest":[
6.9270974,
79.8607731
]
},
"Legs":[
{
"LegId":1,
"Distance":14904,
"Duration":1941,
"StartAddress":"Colombo",
"EndAddress":"Kadawatha",
"StartLocation":[
6.9270974,
79.8612478
],
"EndLocation":[
7.0011125,
79.95000750000001
],
"Ancestors":[
],
"Price":745
},
{
"LegId":2,
"Distance":63040,
"Duration":6209,
"StartAddress":"Kadawatha",
"EndAddress":"Kegalle",
"StartLocation":[
7.0011125,
79.95000750000001
],
"EndLocation":[
7.251436200000001,
80.3466076
],
"Ancestors":[
"Colombo"
],
"Price":3152
},
{
"LegId":3,
"Distance":38990,
"Duration":4430,
"StartAddress":"Kegalle",
"EndAddress":"Kandy",
"StartLocation":[
7.251436200000001,
80.3466076
],
"EndLocation":[
7.2901864,
80.6338425
],
"Ancestors":[
"Colombo",
"Kadawatha"
],
"Price":1950
}
]
},
"TotalPrice":"5847.0",
"SeatCount":1,
"Detour":1,
"Luggage":2,
"DetoursDescription":"10 Minutes",
"LuggageDescription":"Small Luggage",
"Notes":"new ride"
}
when I try to serialize it before send it gives an error:
'NSInvalidArgumentException', reason: '*** +[NSJSONSerialization
dataWithJSONObject:options:error:]: Invalid top-level type in JSON
write'
func synchronusPostRequstWithHeadersJson(apiMethod:String, params:JSON, headers:[ String: String]) -> ResultModel {
let resultModel = ResultModel()
//create the url with URL
let url = URL(string: BASE_URL + apiMethod )!
let session = URLSession.shared
//// **** HERE IT FAILING *****////
let jsonData = try? JSONSerialization.data(withJSONObject: params)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
for item in headers {
request.addValue(item.value, forHTTPHeaderField: item.key)
}
let semaphore = DispatchSemaphore(value: 0)
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
if(error != nil){
resultModel.ErrorType = .NO_INT
resultModel.JsonReslut = JSON.null
}else{
if let resp = response as? HTTPURLResponse{
if(resp.statusCode == 200){
if let jsonResult = JSON(data) as? JSON {
resultModel.ErrorType = .NO_ERROR
resultModel.JsonReslut = jsonResult
}
}else{
if let jsonResult = JSON(data) as? JSON {
resultModel.ErrorType = .SEREVR_ERROR
resultModel.JsonReslut = jsonResult
}else{
resultModel.ErrorType = .SEREVR_ERROR
resultModel.JsonReslut = JSON.null
}
}
}
}
semaphore.signal()
})
task.resume()
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
return resultModel
}
How can i send that request?. Is it possible with alamofire?
Using Almofire you can achieve this as
let params: [String: Any] = [
"StartAddress":"Colombo",
"EndAddress":"Kandy",
"DepartureAddress":"Kollupitiya, Colombo",
"StartLocation":[
6.9270974,
79.8607731
],
"EndLocation":[
7.2916216,
80.6341326
],
] //Do check your dictionary it must be in correct format
Alamofire.request("yourUrl", method: .post, parameters: params, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
}
try using:
let session = Foundation.URLSession.shared
let url = URL(string: "Your server url")
var request = URLRequest(url : url!)
request.httpMethod = "POST"
let params :[String:Any] = ["name":"yuyutsu" as Any,"rollno":12 as Any] //Add your params
do {
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
session.dataTask(with: request, completionHandler: { data, response, error in
OperationQueue.main.addOperation {
guard error == nil && data != nil else { // check for fundamental networking error
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
// print("response = \(response)")
}
let responseString = String(data: data!, encoding: String.Encoding.utf8)
print("responseString = \(responseString!)")
if let responsedata = responseString!.data(using: String.Encoding.utf8)! as? Data{
do {
let jsonResult:NSDictionary = try JSONSerialization.jsonObject(with: responsedata, options: []) as! NSDictionary
print("Get The Result \(jsonResult)")
if error != nil {
// print("error=\(error)")
}
if let str = jsonResult["success"] as? NSNull {
print("error=\(str)")
}
else {
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Response string : \(responseString)")
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
}) .resume()
}catch {
// print("Error -> \(error)")
}
hope this might help you out.
Creating JSON parameters to send it as a post body:
Function:
//MARK:- Create JSON String
func createJSONParameterString(postBody:AnyObject) -> String {
if let objectData = try? JSONSerialization.data(withJSONObject: postBody, options: JSONSerialization.WritingOptions(rawValue: 0)) {
let objectString = String(data: objectData, encoding: .utf8)
return objectString ?? ""
}
return ""
}
Usage:
var postBody = [AnyHashable:Any]()
postBody["device_id"] = "device_ID"
let parameters = createJSONParameterString(postBody: postBody as AnyObject)
print(parameters)
i have solved similar problem using Alamofire and SwiftyJson as follow
let call your object (data )
let json = JSON(data)
let Params :Dictionary = json.dictionaryObject!
and in Alamofire request
Alamofire.request(url, method: .post, parameters: Params , encoding: JSONEncoding.prettyPrinted, headers: nil)
//.validate(statusCode: 200..<300)
.responseJSON { response in
switch response.result
{
case .failure(let error):
case .success(let value):
}
it need to replace this "{ }" with "[ ]"
and alamofire and swift json handle that issue
ex:
[
{
"firstName" : " " ,
"lastName" : " "
},
{
"firstName" : " " ,
"lastName" : " "
}
]
change it to
[
[
"firstName" : " " ,
"lastName" : " "
],
[
"firstName" : " " ,
"lastName" : " "
]
]
I am trying to POST username & password as NSDictionary through JSON format. I am getting this following error :
Domain=NSCocoaErrorDomain Code=3840 "
JSON text did not start with array or object and option to allow fragments not set."
UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
My code is below:
#IBAction func loginAuthentication(_ sender: UIButton) {
let username : NSString = NameTextField.text! as NSString
let password : NSString = passwordTextField.text! as NSString
let parameters = [
"username": "\(username)",
"password": "\(password)"
]
print(parameters)
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
"postman-token": "121b2f04-d2a4-72b7-a93f-98e3383f9fa0"
]
if let postData = (try? JSONSerialization.data(withJSONObject: parameters, options: [])) {
let request = NSMutableURLRequest(url: URL(string: "http://..")!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
print(request.httpBody)
// let session = URLSession.shared
let task = URLSession.shared.dataTask(with: request as URLRequest) {
(data, response, error) -> Void in
if (error != nil) {
print("Error message \(error)")
} else {
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? NSDictionary
{
let success = json["error"] as? Bool
print("Error from php\(success)")
let message = json["message"] as? String
// here you check your success code.
if (success == false)
{
print("Result1 \(message)")
self.performSegue(withIdentifier: "", sender: self)
}
else
{
self.dismiss(animated: true, completion: nil)
print("Result2 \(message)")
}
}
})
}
}
task.resume()
}
}
The problem looks to me like your string is not being serialized correctly. Instead of your current json serialization approach, simply convert a swift dictionary to data.
//Start with a dictionary
let body = [
"username": "bob",
"password": "admin"
]
//Serialize it.... you might want to put this in a do try catch block instead
let jsonBody = try? JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
//Add it to the request
request.httpBody = jsonBody
//make the request, etc.
let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response, error in
This is my first application i am working on.I have one api url for login calling function. And when i enter username, password. It will generate one customer id.And i need to save that is, and i have to use that particular id for all my screen till user logged out.
But when i am doing api calling for login . Its not working. Please help me out.
This is my parameter passing :
{
"username" : "u#gmail.com",
"password" : "u123"
}
My json output after login api call :
{
"status": 1,
"message": "Login success.",
"CustomerDetails": {
"CustomerId": "1",
"CustomerName": "u",
"CustomerEmail": "u#gmail.com",
"CustomerMobile": "901",
"CustomerAddress": "#45, 7th main road."
}
}
In this i need to save the CustomerId and i have to use that CustomerId to all my screens.
My api calling fuction while login button tap :
func getcartdetaildata () {
let headers = [
"cache-control": "no-cache",
"postman-token": "4c933910-0da0-b199-257b-28fb0b5a89ec"
]
let jsonObj:Dictionary<String, Any> = [
"username" : "\(UsernameEmail)",
"password" : "\(Password)"
]
if (!JSONSerialization.isValidJSONObject(jsonObj)) {
print("is not a valid json object")
return
}
if let postData = try? JSONSerialization.data(withJSONObject: jsonObj, options: JSONSerialization.WritingOptions.prettyPrinted) {
let request = NSMutableURLRequest(url: NSURL(string: "http://Login.php")! as URL,
cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
///print(error)
} else {
print("123.......... ")
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? Dictionary<String,AnyObject>
{
print(json)
let status = json["status"] as? Int;
if(status == 1)
{
print("asdasdasx.......... ")
// let access_token = json["CustomerId"]
//print(access_token)
DispatchQueue.main.async(execute: {
//
//
// //Set logged in to true
// UserDefaults.standard.set(true, forKey: "ISLOGGEDIN")
//
// //Set access token
// UserDefaults.standard.setValue(access_token, forKey: "CustomerId")
//
// UserDefaults.standard.synchronize()
//
})
}
}
})
}
})
dataTask.resume()
}
}
Please help me out.
Thanks
func apicalling () {
let Username:NSString = EmailTextField.text! as NSString
let password:NSString = PasswordTextField.text! as NSString
let headers = [
"content-type": "application/json",
"cache-control": "no-cache",
"postman-token": "4c933910-0da0-b199-257b-28fb0b5a89ec"
]
let parameters = [
"username": "\(Username)",
"password": "\(password)"
]
do {
let postData = try JSONSerialization.data(withJSONObject: parameters, options :[])
let request = NSMutableURLRequest(url: NSURL(string: "http://Login.php")! as URL,cachePolicy: .useProtocolCachePolicy,timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
///print(error)
} else {
DispatchQueue.main.async(execute: {
if let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? Dictionary<String,AnyObject>
{
let status = json["status"] as? Int;
if(status == 1)
{
print(json)
}
}
})
}
})
dataTask.resume()
} catch {
// print("JSON serialization failed: \(error)")
}
}
Code for save data in NSUserDefaults.
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue(YOUR_VALUE, forKey: "PASSKEY")
userDefaults.synchronize() // don't forgot this line
Retriving data from NSUserDefaults
if let VARIABLE = userDefaults.valueForKey("PASSKEY") {
// do something here when a Data exists
}
else {
// no data exists
}