Parsing nested Json data in swift 3 - json

I am getting unexpected values back when i am parsing my json data from my api, i may be doing something wrong here as i'm quite new to swift but i was getting correct values before when i was receiving one "key" but now i have added two i cannot seem to parse the values properly.
This is the json collected from the address my code is receiving, (sorry if its hard to read havn't worked out how to do line breaks yet in my ruby api)(as long as its functional im not too worried at the moment)
{
"ratings":{
"elements":{"Ready Position":[{"description":"Neutral Grip","values":"1,2,3,4,5"},{"description":"Back Straight (Concave ir Convex?)","values":"1,2,3,4,5"},{"description":"Body Low \u0026 Feet a little more than sholder width apart","values":"1,2,3,4,5"},{"description":"Weight on Balls of Feet","values":"1,2,3,4,5"},{"description":"Head Up","values":"1,2,3,4,5"},{"description":"Sholder Blades Close","values":"1,2,3,4,5"},{"description":"Eyes Drilled","values":"1,2,3,4,5"}],"Split Step":[{"description":"Ready Position Conforms","values":"Yes,No"},{"description":"Body Position Low","values":"1,2,3,4,5"},{"description":"Legs Loaded/Prepared","values":"1,2,3,4,5"}]}
},
"comments":{}
}
Now, My swift code looks like this
let playerAPIurl = "http://linkcoachuat.herokuapp.com/api/v1/session/element?organisation=" + userorganisation + "&group=" + urlGroupSelected + "&sport=" + usersport
print(playerAPIurl)
var request = URLRequest(url: URL(string: playerAPIurl)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print("ERROR")
}
else{
do {
let json = try JSONSerialization.jsonObject(with: data!) as? [String: AnyObject]
print(json)
And this is the output im getting from this print(json)
Optional({
comments = {
};
ratings = {
};
})
I know i shouldnt be getting anything more in the comments part, but in the ratings part there should be some data?
so after recieving the json and dealing with parsing it i need to access this part of it ["ratings"]["elements"] and after that im all good
thanks in advance and please bare in mine im very new to swift
Thanks

Try the below code. The url used in below code has your JSON data. This code is printing the output correctly.
func testApi(){
let url = URL(string: "https://api.myjson.com/bins/jfccx")
let session = URLSession.shared
let request = URLRequest(url: url!)
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard let data = data, error == nil else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print(json)
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}

Related

How to access JSON response within URLSession of HTTP Post request?

I'm making an http post request within the XCTest framework in Xcode for a simple UI test for my app. Within the request, the response is returned. I can't access that response outside of the URLSession task, and I need to because it contains a JWT that must be decoded and used for another http post request.
I've tried researching how to do this, but it is hard to know the right path as I am a beginner in Swift. I've tried creating a new json object and assigning that response to it outside of the URLSession, but it just says that it can't find that response, it is outside of scope.
// make HTTP request
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
let response = responseJSON as! [String:Any]
The expected results are that I now have my response object outside of the http request and I can then decode it. The actual results is the error:
Use of unresolved identifier 'responseJSON'
The request your making is asynchronous. So when you run the line...
let response = responseJSON as! [String:Any]
the network request hasn't finished yet. So you would normally use a completion handler that will be called when the network returns
Here is an example playground:
//: Playground - noun: a place where people can play
import PlaygroundSupport
import UIKit
PlaygroundPage.current.needsIndefiniteExecution = true
func postSomeData(completion: #escaping ([String: Any]?, Error?) -> Void) {
// setup request
let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")
let request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
completion(nil, error)
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
completion(responseJSON, nil)
}
}
task.resume()
}
postSomeData() { response, error in
print(response, error)
PlaygroundPage.current.finishExecution()
}
Output:
Optional(["id": 1, "title": delectus aut autem, "completed": 0, "userId": 1]) nil
I would also suggest that you use Codable for parsing and mapping the JSON response. Here is an intro to using Codable but there are lots of resources available online on the subject.

Error to parse a JSON file in Swift 3

I´m newbie in Swift and I have some problems with parsing JSON using Swift 3 code.
This is my JSON (extract):
[
{
"COD_USUARIO":"4",
"0":"4",
"USUARIO":"PIEDAD",
"1":"PIEDAD",
"CLAVE":"MU\u00d1OZ",
"2":"MU\u00d1OZ",
"ACTIVO":"1",
"3":"1",
"FECHA_ALTA":"2010-12-07 00:00:00",
"4":"2010-12-07 00:00:00",
"FECHA_BAJA":null,
"5":null,
"CIF":null,
"6":null,
"TELEFONO_CASA":"",
"7":"",
"TELEFONO_MOVIL":"",
"8":"",
"EMAIL_TRABAJO":"",
"9":"",
"EMAIL_PARTICULAR":"",
"10":"",
"COLOR":"16777215",
"11":"16777215",
"ADMINISTRADOR":"0",
"12":"0",
"COD_PERSONA":"9",
"13":"9",
"IMPRESORA_ETIQUETAS":"",
"14":"",
"IMP_JUSTIFICANTES":"",
"15":"",
"VER_SESIONES":"0",
"16":"0",
"COD_EMPRESA":"0",
"17":"0",
"FECHA_TRABAJO":null,
"18":null,
"MEMORIZAR_FECHA":"0",
"19":"0",
"AVISOS_PAGOS":"0",
"20":"0",
"AVISOS_COBROS":"0",
"21":"0",
"AVISOS_DIAS":"0",
"22":"0",
"AVISOS_CONTRATOSC":"0",
"23":"0",
"24":"0"
}
]
And this is my code (extract):
let url = URL(string : "http://192.168.0.252:6996/datos/policlinica/webservices/valida.php")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"
let paramToSend = "usu=" + user + "&pass=" + pwd
request.httpBody = paramToSend.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
guard let _:Data = data else{
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
print (json) //I can see my json in console
let cod_persona = json["COD_USUARIO"]
print (cod_persona)
//error: Type 'Any' has no subscript members
} catch {
print ("error")
return
}
})
task.resume()
I have tried many examples of the internet, but I can not read a specific JSON data. For example, I would like to read the "COD_USUARIO" field and save the data in a variable, but I can not get it to work well for me.
Any advice on this theme or what am I doing wrong (sure many things)
I think your problem is that your json contains array objects, so I would call it like:
json[0]["COD_USUARIO"]
Because COD_USUARIO is in the first array of the json.

Swift cannot convert json array to a NSArray

I am trying to get a json data from webpage and put it into my app. I have search so many things online and do not find any of them solve my problem.
The sample json is here
[{"id":"1","name":"Clean Archutecture","ISBN":"9780134494166","phone":null,"email":null,"comment":null,"last_update":"2018-03-10 22:53:29","price":"40","type":"sell"},{"id":"2","name":"Math Book","ISBN":null,"phone":null,"email":null,"comment":null,"last_update":"2018-03-10 22:53:54","price":null,"type":"want"},{"id":"3","name":"abc","ISBN":null,"phone":"hi","email":null,"comment":null,"last_update":"2018-03-11 19:58:00","price":"14.5","type":"want"},{"id":"4","name":"asd","ISBN":"1234","phone":"546","email":"dgf#asdc.com","comment":"234","last_update":"2018-03-11 19:59:57","price":"123","type":"want"}]
Swift code:
import Foundation
import UIKit
class Books: NSObject{
let urlRootPath = "http://maichongju.com/dbbs.php"
let method = "GET" //This is design for the php
func getData(type:String){
var result = NSArray()
let urlPath: String = urlRootPath+"?method=GET&size=ALL"
let url: URL = URL(string: urlPath)!
let request: NSMutableURLRequest = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request as URLRequest){
data,response, error in
if error != nil{
print("error:!! \(String(describing: error))")
return
}
do {
result = try JSONSerialization.jsonObject(with: data!, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
print(result )
}catch {
print(error)
}
//print(result)
}
task.resume()
}
}
Error message is
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around
character 0." UserInfo={NSDebugDescription=Invalid value around
character 0.}
I have double check my json data, i put it into online json view and it show perfectly fine. And I really dont know how to fix this problem
You don't need to force cast json response
do like this:
jsonResponse = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
Convert it like this as this is Array of Dictioanry objects
if let responseArray: [[String:Any]] = jsonResponse as? [[String:Any]] {
// DO HERE
}
I hope this will work for you
For safe side you https://github.com/Alamofire/Alamofire for Network request and for JSON : https://github.com/SwiftyJSON/SwiftyJSON
Update:
let urlPath: String = urlRootPath+"?method=GET&size=ALL"
i think is incorrect, In your body you have added POST but in URL you are appending method=GET
request.httpMethod = "POST"

Swift: send POST request with JSONEncoder encoded data does not work

I am using the JSONEncoder that has been provided with Swift4.
I have a class called Customer that uses the Codable protocol. Inside of Customer there are four Strings.
class Customer: Codable {
var title: String
var firstName: String
var lastName: String
var email: String
}
Reading JSON with a GET Request works fine.
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
do {
let customer = try JSONDecoder().decode(Customer.self, from: data)
DispatchQueue.main.async {
print("\(customer.title)")
print("\(customer.firstName)")
print("\(customer.lastName)")
print("\(customer.email)")
}
} catch let jsonError {
print(jsonError)
}
}.resume()
However when I start to do a POST request I am lost:
First set up the request object:
let urlString = "http://localhost:8000/customer"
guard let url = URL(string: urlString) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
let customer = Customer()
customer.title = "Mr"
customer.firstName = "Chuck"
customer.lastName = "Norris"
customer.email = "chuck.norris#awsome.com"
let encodedData = try? JSONEncoder().encode(customer)
print(String(data: encodedData!, encoding: .utf8)!) //<- Looks as intended
// Output is {"firstName":"Chuck","lastName":"Norris","title":"MR","email":"chuck.norris#awesome.com "}
Now send it out
request.httpBody = encodedData //
URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.data(withJSONObject: data, options: [])
print(json)
}catch {
print(error)
}
}
})
In return I receive the message "The given data was not valid JSON."
So, my assumption is that I simply can not just put the encoded JSON data into the http body of my request.
Browsing through some articles about URLSession and JSON I found that it seems that I need to serialize my encoded JSON:
var json: Any?
if let data = encodedData {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
}
Now, I don't know how to proceed. First I do not understand why I should serialize my JSON to something that can not simply put into a httpBody.
Because JSONSerialization.jsonObject produces Any? and not Data.
Update
Now, I was able to successfully send my data to my server. I am still trying to understand what was wrong - because I did not changed anything (except for the removal of the JSONSerialization call inside the completion Handler. I will investigate further...
...And .resume had been missing. :-)

Trouble converting JSON to data with Swift

I am trying to learn Swift. One of my projects is to try to retrieve JSON data from an internal web service (a group of Python CGI scripts) and convert it into a Swift object. I can do this easily in Python, but I am having trouble doing this in Swift. Here is my playground code:
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
let endpoint: String = "http://pathToCgiScript/cgiScript.py"
let url = NSURL(string: endpoint)
let urlrequest = NSMutableURLRequest(URL: url!)
let headers: NSDictionary = ["User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)",
"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"]
urlrequest.allHTTPHeaderFields = headers as? [String : String]
urlrequest.HTTPMethod = "POST"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(urlrequest) {
(data, response, error) in
guard data != nil else {
print("Error: did not receive data")
return
}
guard error == nil else {
print("Error calling script!")
print(error)
return
}
do {
guard let received = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as?
[String: AnyObject] else {
print("Could not get JSON from stream")
return
}
print(received)
} catch {
print("error parsing response from POST")
}
}
task.resume()
I know making a 'POST' to retrieve data may look odd, but that is how the system is set up. I keep on getting:
Could not get data from JSON
I checked the response, and the status is 200. I then checked the data's description with:
print(data?.description)
I got an unexpected result. Here is a snippet:
Optional("<0d0a5b7b 22535441 54555322 3a202244 6f6e6522 2c202242 55535922...
I used Mirror, and apparently the type is NSData. Not sure what to make of this. I have tried to encode the data with base64EncodedDataWithOptions. I have tried different NSJSONReadingOptions as well to no avail. Any ideas?
Update:
I used Wireshark to double check the code in the Playground. Not only was the call made correctly, but the data being sent back is correct as well. In fact, Wireshark sees the data as JSON. The issue is trying to turn the JSON data into a Swift object.
I figured out what was wrong. I was casting to the wrong type. This is the new code:
guard let received = try! NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? [AnyObject]
The JSON was not returning an array of dictionaries but an array of objects.