Swift 4 JSON decoding - json

I am trying to decode JSON. My swift function for decoding the JSON is:
func GetChapInfo(){
let endpoint = "https://chapel-logs.herokuapp.com/chapel"
let endpointUrl = URL(string: endpoint)
do {
var request = URLRequest(url: endpointUrl!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request){
(data: Data?, response: URLResponse?, error: Error?) in
let dataAsString = String(data: data!, encoding: .utf8)
//print(dataAsString)
if(error != nil) {
print("Error")
}
else{
do{
guard let chapData = try? JSONDecoder().decode(Chapel.self, from: data!) else {
print("Error: Couldn't decode data into chapData")
return
}
for E in chapData.chap {
print(E.Day as Any)
}
}
}
}
task.resume()
}
}
my struct in Swift is
struct Chapel: Decodable {
let chap: [Chap]
}
struct Chap: Decodable {
let Name: String?
let Loc: String?
let Year: Int?
let Month: Int?
let Day: Int?
let Hour: Int?
let Min: Int?
let Sec: Int?
}
and my response from the server is:
{"chap":{"Name":"Why Chapel","Loc":"FEC","Year":2018,"Month":9,"Day":4,"Hour":16,"Min":1,"Sec":7}}
However when I run this the program prints out "Error: Couldn't decode data into chapData" and I cannot figure out why.

First of all catch decoding errors. Never try?. The caught error is much more descriptive
Expected to decode Array<Any> but found a dictionary instead
Means: The value for key chap is a dictionary, not an array
struct Chapel: Decodable {
let chap: Chap
}
And then you have to print
print(chapData.chap.Day)
You can reduce your code. An explicit URLRequest and headers for a default GET request is not needed. This is sufficient:
let endpoint = "https://chapel-logs.herokuapp.com/chapel"
let endpointUrl = URL(string: endpoint)!
do {
let task = URLSession.shared.dataTask(with: endpointUrl) { (data, response, error) in
...

Related

Unable to get JSON response with Decodable in Swift

in postman response structure like this:
{
"categories": [
{
"id": 48,
"name": "Round-The-Clock",
"description": "24 hours round the clock menu",
"status": "enabled",
"products": [
{
"id": 280,
"name": ".Tea",.....
for this i have created Decodable model like this
struct Categories: Codable {
let categories: [Category]?
let featuredProducts: [Product]?
//coding keys..
}
struct Category: Codable {
let id: Int?
let name, categoryDescription: String?
let products: [Product]?
}
struct Product: Codable {
let id: Int?
let name, productDescription: String?
}
Parsing code: with this code break point hits with this if let jsonData = try? decoder.decode(Categories.self, from: respData) line but not hitting print("the categories are: (jsonData)") line and nothing comes in console, why? where am i wrong.. how to get response
class FoodMenuViewController: UIViewController {
private var catData: Categories? {
didSet{ }
}
func foodMenuServicecall(){
let urlStr = "http://54.149.84.126/categories?shop=1"
let url = URL(string: urlStr)
var req = URLRequest(url: url!)
req.httpMethod = "GET"
req.addValue("X-Requested-With", forHTTPHeaderField: "Content-Type")
req.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
guard let respData = data else {return}
guard error == nil else {
print("error")
return
}
do{
let decoder = JSONDecoder()
if let jsonData = try? decoder.decode(Categories.self, from: respData) {
print("the categories are: \(jsonData)")
self.catData = jsonData
}
}
catch {print("catch error")}
}).resume()
}
EDIT: if i test like this i am getting response but here
func foodMenuServicecall(){
if let url = URL(string: "http://54.149.84.126//categories?shop=1"){
var req = URLRequest(url: url)
req.allHTTPHeaderFields = ["X-Requested-With" : "XMLHttpRequest"]
URLSession.shared.dataTask(with: req) { data, _, err in
guard let safeData = data else{return}
print(String(data: safeData, encoding: .utf8) ?? "")
}.resume()
}
}
o/p in consol:
Your decodable model expects a key of "categoryDescription", your JSON has a key of "description".

How to get particular 'json' value in swift 5?

I want the 'success' value in json object but the problem is I'm getting whole json data I want only 'success' value to print
Here is my json`
{
response = {
success = 1;
successmsg = "Successful Connection";
};
}`
Here is my code in swift 5
#IBAction func girisButtonTap(_ sender: Any) {
var txtusername: String
var txtpassword: String
txtusername = usercodeText.text!
txtpassword = passwordText.text!
let Url = String(format: "http://10.10.10.53:8080/sahambl/rest/sahamblsrv/userlogin")
guard let serviceUrl = URL(string: Url) else { return }
let parameters: [String: Any] = [
"request": [
"xusercode" : "\(txtusername)",
"xpassword": "\(txtpassword)"
]
]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
let session = URLSession.shared
struct ResponseJSON: Codable {
let response: Response
}
struct Response: Codable {
let success: Int
let successmsg: String
}
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONDecoder().decode(ResponseJSON.self, from: data)
print(json)
let successful = json.response.success == 1
} catch {
print(error)
}
}
}.resume()
}
}
I would be grateful for any progress.
Use a model struct and Codable for parsing:
struct ResponseJSON: Codable {
let response: Response
}
struct Response: Codable {
// depending on what your JSON actually looks like, this could also be
// let success: Bool
let success: Int
let successmsg: String
}
session.dataTask(with: request) { data, response, error in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONDecoder().decode(ResponseJSON.self, from: data)
print(json)
// access the success property:
let successful = json.response.success == 1
// leave off the "== 1" if it's a Bool
} catch {
print(error)
}
}
}.resume()

Swift and JSON driving me crazy

I am really getting stuck on this.
I have created a JSON service, that returns data like this:
[
{
"docNameField": "Test",
"docNumField": 22832048,
"docVerField": 1,
"docDataBaseField": "Legal",
"docCheckedOutWhenField": "03/05/2020",
"whereCheckedOutField": "PC0X8J9RD"
}
]
This is Postman output.
No matter how I try, I cannot seem to be able to put together the correct combination og HTTP call, deserialization, types and so on to get a list of objects out in the end.
This func below outputs this:
JSON String: Optional("[{\"docNameField\":\"Test\",\"docNumField\":22832048,\"docVerField\":1,\"docDataBaseField\":\"Legal\",\"docCheckedOutWhenField\":\"03/05/2020\",\"whereCheckedOutField\":\"PC0X8J9RD\"}]")
func LoadLockedDocumentsByDocnum(docNum:Int32) {
let json: [String: Any] = ["action":"getCheckedOutDocuments","adminUserName":"\(APPuserName)","adminPassword":"\(APPuserPassword)","adminDomain":"\(APPuserDomain)","applicationKey":"19730905{testKey}","searchTerm":docNum]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
self.documentEntries.removeAll()
let url = URL(string: "https://{URL}//CheckOut")!
var request = URLRequest(url: url)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") //Optional
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if let resultat = response as! HTTPURLResponse?{
if resultat.statusCode == 200{
if error != nil {
}
else {
print(data!)
if let nydata = data{
print("JSON String: \(String(data: data!, encoding: .utf8))")
}
}
}}
}
dataTask.resume()
}
You seem to have come pretty close. To get a list of objects out, you first need to declare that object:
struct MyResponseObject: Decodable { // please give this a better name
let docNameField: String
let docNumField: Int
let docVerField: Int
let docDataBaseField: String
let docCheckedOutWhenField: Date
let whereCheckedOutField: String
}
And then use a JSONDecoder to deserialise the JSON. Instead of:
print("JSON String: \(String(data: data!, encoding: .utf8))")
write:
let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"
decoder.dateDecodingStrategy = .formatted(formatter)
do {
// here's your list of objects!
let listOfObjects = try decoder.decode([MyResponseObject].self, from: data!)
} catch let error {
print(error) // an error occurred, you can do something about it here
}

How to parse JSON using swift 4

I am confusing to getting detail of fruit
{
"fruits": [
{
"id": "1",
"image": "https://cdn1.medicalnewstoday.com/content/images/headlines/271/271157/bananas.jpg",
"name": "Banana"
},
{
"id": "2",
"image": "http://soappotions.com/wp-content/uploads/2017/10/orange.jpg",
"title": "Orange"
}
]
}
Want to parse JSON using "Decodable"
struct Fruits: Decodable {
let Fruits: [fruit]
}
struct fruit: Decodable {
let id: Int?
let image: String?
let name: String?
}
let url = URL(string: "https://www.JSONData.com/fruits")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else { return }
do{
let fruits = try JSONDecoder().decode(Fruits.self, from: data)
print(Fruits)
}catch {
print("Parse Error")
}
also can you please suggest me cocoapod library for fastly download images
The issue you are facing is because your JSON is returning different data for your Fruits.
For the 1st ID it returns a String called name, but in the 2nd it returns a String called title.
In addition when parsing the JSON the ID appears to be a String and not an Int.
Thus you have two optional values from your data.
As such your Decodable Structure should look something like this:
struct Response: Decodable {
let fruits: [Fruits]
}
struct Fruits: Decodable {
let id: String
let image: String
let name: String?
let title: String?
}
Since your URL doesn't seem to be valid, I created the JSON file in my main bundle and was able to parse it correctly like so:
/// Parses The JSON
func parseJSON(){
if let path = Bundle.main.path(forResource: "fruits", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONDecoder().decode(Response.self, from: data)
let fruitsArray = jsonResult.fruits
for fruit in fruitsArray{
print("""
ID = \(fruit.id)
Image = \(fruit.image)
""")
if let validName = fruit.name{
print("Name = \(validName)")
}
if let validTitle = fruit.title{
print("Title = \(validTitle)")
}
}
} catch {
print(error)
}
}
}
Hope it helps...
// Parse Json using decodable
// First in create Structure depends on json
//
//
//
struct Countory : Decodable {
let name: String
let capital: String
let region: String
}
let url = "https://restcountries.eu/rest/v2/all"
let urlObj = URL(string: url)!
URLSession.shared.dataTask(with: urlObj) {(data, responds, Error) in
do {
var countories = try JSONDecoder().decode([Countory].self, from: data!)
for country in countories {
print("Country",country.name)
print("###################")
print("Capital",country.capital)
}
} catch {
print(" not ")
}
}.resume()
Model sample:
public struct JsonData: Codable{
let data: [Data]?
let meta: MetaValue?
let linksData: LinksValue?
private enum CodingKeys: String, CodingKey{
case data
case meta
case linksData = "links"
}
}
enum BackendError: Error {
case urlError(reason: String)
case objectSerialization(reason: String)
}
struct APIServiceRequest {
static func serviceRequest<T>(reqURLString: String,
resultStruct: T.Type,
completionHandler:#escaping ((Any?, Error?) -> ())) where T : Decodable {
guard let url = URL(string: reqURLString) else {
print("Error: cannot create URL")
let error = BackendError.urlError(reason: "Could not construct URL")
completionHandler(nil, error)
return
}
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest) { (data, response, error) in
guard error == nil else {
completionHandler(nil, error)
return
}
guard let responseData = data else {
print("Error: did not receive data")
let error = BackendError.objectSerialization(reason: "No data in response")
completionHandler(nil, error)
return
}
let decoder = JSONDecoder()
do {
let books = try decoder.decode(resultStruct, from: responseData)
completionHandler(books, nil)
} catch {
print("error trying to convert data to JSON")
print(error)
completionHandler(nil, error)
}
}
task.resume()
}
}
To Access:
let apiService = APIServiceRequest()
var dataArray: [String: Any]? //global var
apiService.serviceRequest(reqURLString: endPoint, resultStruct: VariantsModel.self, completionHandler: {dataArray,Error in})
POST Method
func loginWS(endpoint: String, completionHandler: #escaping (Any?) -> Swift.Void) {
guard let sourceUrl = URL(string: endpoint) else { return }
let request = NSMutableURLRequest(url: sourceUrl)
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue(vehiceHeader, forHTTPHeaderField: "X-Vehicle-Type")
request.addValue(contentHeader, forHTTPHeaderField: "Content-Type")
let task = session.dataTask(with: request as URLRequest) { data, response, error in
guard let data = data else { return }
do {
let responseData = try JSONDecoder().decode(JsonData.self, from: data)
print("response data:", responseData)
completionHandler(responseData)
} catch let err {
print("Err", err)
}
}.resume()
}

JSonDecoder() Swift 4 Decoding error

I am getting an error when trying to decode Json in swift 4
typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [Swift._DictionaryCodingKey(stringValue: "ThrottleSeconds", intValue: nil)], debugDescription: "Expected to decode Dictionary but found a number instead.", underlyingError: nil))
Json reply is
{"Response":"4611686018456390681","ErrorCode":1,"ThrottleSeconds":0,"ErrorStatus":"Success","Message":"Ok","MessageData":{}}
struct BasicReply: Decodable {
let Response : String?
let ErrorCode : Int?
let ThrottleSeconds : Int?
let ErrorStatus : String?
let Message : String?
let MessageData : String?
}
class NetworkRequests {
let api = apiDetails()
func buildRequests()->String{
let request = "1/Stats/GetMembershipIdByDisplayName/" + api.userName + "/"
// let request = "1/Account/" + api.membershipId + "/Summary/"
return request
}
func request(){
let destinyURL : String = api.destinyURL + buildRequests()
let url = NSURL(string: destinyURL)
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "GET"
// add headers
request.setValue(api.apiKey, forHTTPHeaderField: "X-API-Key")
let session = URLSession.shared
let destinySession = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let response = response as? HTTPURLResponse {
let code = response.statusCode
print(code)
}
guard let data = data else {print("No DATA!!!");return}
let output = String(data: data, encoding: String.Encoding.utf8)
print("output ", output! as Any)
do {
let questions = try JSONDecoder().decode([String: BasicReply].self, from: data)
} catch let jsonErr {
print("Error decoding Json Questons", jsonErr)
}
}
destinySession.resume()
}
}