Parsing the JSON iOS-Swift - ios

I have a JSON response that I am parsing with the help of codable models.
Even though my models look good, I am getting the following error:
[Result]: FAILURE: keyNotFound(CodingKeys(stringValue: “user”, intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: “No value associated with key CodingKeys(stringValue: \“user\“, intValue: nil) (\“user\“).“, underlyingError: nil))
The JSON response is:
{
“status”: “success”,
“message”: “successfully.“,
“user”: {
“username”: “admin”,
“profileImage”: “/storage/default.png”
},
“data”: {
“cash”: {
“withdrawableCash”: “$999540”,
“outstandingOrders”: “$0”
},
“offering”: [
{
“company”: “ABCD”,
“location”: “San Francisco, CA”,
“amount”: 10
}
],
“history”: [
{
“amount”: 330,
“order_id”: 3,
“order_type”: “preBid”,
“status”: 2,
“message”: “Placed bid with 33 notes, on Auction,
“transaction_time”: “31-07-2018 05:31"
}
]
}
}
The models are:
public struct WalletResponseModel: Codable {
public let status: String
public let message: String
public let user: UserData
public let data: WalletData
}
public struct UserData: Codable {
public let username: String
public let profileImage: URL
enum CodingKeys: String, CodingKey {
case username
case profileImage = "profileImage"
}
}
public struct WalletData: Codable {
public let cash: Cash
public let history: [HistoryItem]
public let offerings: [Offering]
enum CodingKeys: String, CodingKey {
case cash
case history
case offerings = "offering"
}
}
public struct Cash: Codable {
public let withdrawableCash: String
public let outstandingOrders: String
}
public struct HistoryItem: Codable {
public let amount: Int
public let status: Int
public let orderId: Int
public let orderType: String
public let message: String
public let transactionTime: String
enum CodingKeys: String, CodingKey {
case amount, status, message
case transactionTime = "transaction_time"
case orderId = "order_id"
case orderType = "order_type"
}
}
public struct Offering: Codable {
public let company: String
public let amount: Int
public let location: String
}

Your json format is incorrect it contains “ ” instead of " " , the valid one is
{
"status": "success",
"message": "successfully.",
"user": {
"username": "admin",
"profileImage": "/storage/default.png"
},
"data": {
"cash": {
"withdrawableCash": "$999540",
"outstandingOrders": "$0"
},
"offering": [{
"company": "ABCD",
"location": "San Francisco, CA",
"amount": 10
}],
"history": [{
"amount": 330,
"order_id": 3,
"order_type": "preBid",
"status": 2,
"message": "Placed bid with 33 notes, on Auction",
"transaction_time": "31-07-2018 05:31"
}]
}
}

Related

Elegant solutions to decoding a JSON nested array in swift using decodable

Currently working with an API, and while I have successfully gotten it to decode the full result, I am only interested in the Entities/identifier portion. While I have gotten it working and get what I want/need I feel like this could be done better and more elegant and maybe in a single step. Any insight/suggestions appreciated.
JSON returned from API:
{
"count": 4596,
"entities": [
{
"facet_ids": [
"contact",
"siftery",
"investor",
"ipqwery",
"aberdeen",
"apptopia",
"semrush",
"company",
"rank",
"builtwith",
"bombora",
"key_event"
],
"identifier": {
"uuid": "468bef9f-2f50-590e-6e78-62e3adb05aa1",
"value": "Citi",
"image_id": "v1417152861/pdgwqt8ddecult5ktvdf.jpg",
"permalink": "citigroup",
"entity_def_id": "organization"
},
"short_description": "Citigroup is a diversified financial services holding company that provides various financial products and services."
},
{
"facet_ids": [
"contact",
"siftery",
"investor",
"apptopia",
"semrush",
"company",
"rank",
"builtwith",
"key_event"
],
"identifier": {
"uuid": "031a344b-c2b9-e60b-d950-1ae062026fde",
"value": "Citi",
"image_id": "yzlzhjqpparamrswaqa1",
"permalink": "citi-2",
"entity_def_id": "organization"
},
"short_description": "CITi is an NPO supporting the ICT sector in Western Cape."
},
{
"facet_ids": [
"contact",
"siftery",
"semrush",
"company",
"rank",
"builtwith",
"bombora"
],
"identifier": {
"uuid": "7ce45379-957c-49c5-bca2-c9ffd521f7da",
"value": "CITI",
"image_id": "qbkqndm7d0wgbogxjcrs",
"permalink": "citi-f7da",
"entity_def_id": "organization"
},
"short_description": "CITI trusted gateway to project-based change expertise that major organisations need to thrive, change and innovate."
}
]
}
Structs:
struct Entity: Decodable, Identifiable
{
var id: String
var companyName: String
var permalink: String
var imageID: String
init(from entity: Entities.Entity) throws
{
self.id = entity.identifier?.uuid ?? ""
self.companyName = entity.identifier?.value ?? ""
self.permalink = entity.identifier?.permalink ?? ""
self.imageID = entity.identifier?.image_id ?? ""
}
}
struct Entities: Decodable
{
var count:Int?
var entities: [Entity]?
struct Entity: Decodable
{
var facet_ids:[String]?
var identifier:Identifier?
var short_description:String?
}
struct Identifier:Decodable
{
var permalink:String?
var value:String?
var image_id:String?
var entity_def_id:String?
var uuid:String?
}
}
Call to decode:
if let data = data{
do {
let businessEntities = try decoder.decode(Entities.self, from: data)
let entities:[Entity] = try businessEntities.entities!.compactMap{
entity in
do
{
return try Entity(from: entity)
}
}
Thinking you are just interested in the Entities/identifier, you can simplify your model. Here's an example:
typealias Entities = [Entitie]
struct Entitie: Codable {
let facetIDS: [String]
let identifier: Identifier
let shortDescription: String
enum CodingKeys: String, CodingKey {
case facetIDS = "facet_ids"
case identifier
case shortDescription = "short_description"
}
}
struct Identifier: Codable {
let uuid, value, imageID, permalink: String
let entityDefID: String
enum CodingKeys: String, CodingKey {
case uuid, value
case imageID = "image_id"
case permalink
case entityDefID = "entity_def_id"
}
}
You can access entities object and decode it like this:
guard let data = data,
let jsonDict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let entitiesObj = jsonDict["entities"] else { return }
do {
let entitiesData = try JSONSerialization.data(withJSONObject: entitiesObj)
let result = try JSONDecoder().decode(Entities.self, from: entitiesData)
} catch {
print(error.localizedDescription)
}
Obs: I created the CodingKeys because I use camelCase in my projects, you can left it in snake_case just remember to replace variables.

How to configure model class for nested JSON response with Alamofire and Decodable in iOS

I'm using Alamofire and Decodable for a Google Books API request for performing a search.
I've created a Decodable model which I will add below and it worked up until I try to get any other field below "title" in "volumeInfo" (I've been commenting out properties one by one to check where it fails). The error I get after uncommenting "authors", "publisher" or anything other than "title" inside "volumeInfo" is:
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "publisher", intValue: nil)
An example response is:
{
"kind": "books#volume",
"id": "Ett09eLWE5oC",
"etag": "WIwTdsmpnhs",
"selfLink": "https://www.googleapis.com/books/v1/volumes/Ett09eLWE5oC",
"volumeInfo": {
"title": "The Picture of Dorian Gray",
"authors": [
"Oscar Wilde"
],
"publisher": "Wordsworth Editions",
"publishedDate": "1992",
"description": "The handsome appearance of dissolute young Dorian Gray remains unchanged while the features in his portrait become distorted as his degeneration progresses",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "1853260150"
},
{
"type": "ISBN_13",
"identifier": "9781853260155"
}
],
"readingModes": {
"text": false,
"image": true
},
"pageCount": 312,
"printType": "BOOK",
"categories": [
"Fiction"
],
"averageRating": 4.0,
"ratingsCount": 6,
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "1.1.2.0.preview.1",
"panelizationSummary": {
"containsEpubBubbles": false,
"containsImageBubbles": false
},
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=Ett09eLWE5oC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=Ett09eLWE5oC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.ro/books?id=Ett09eLWE5oC&pg=PA130&dq=9781853260155&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.ro/books?id=Ett09eLWE5oC&dq=9781853260155&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/The_Picture_of_Dorian_Gray.html?hl=&id=Ett09eLWE5oC"
}
}
My model:
struct Response: Decodable {
struct VolumeInfo: Decodable {
var title: String
//var authors: [String]
var publisher: String
//var identifiers: [Identifier]
//var image: ImageLink
enum CodingKeys: String, CodingKey {
case title
//case authors
case publisher
//case identifiers = "industryIdentifiers"
//case image = "imageLinks"
}
}
struct Identifier: Decodable {
var type: String
var identifier: String
enum CodingKeys: String, CodingKey {
case type
case identifier
}
}
struct ImageLink: Decodable {
var url: URL
enum CodingKeys: String, CodingKey {
case url = "thumbnail"
}
}
var id: String
var volumeInfo: VolumeInfo
}

Swift Codable Json Response

I Have the following JSON response from API,
{
"status_code": 1000,
"data": [
{
"id": 3,
"invoice_id": 100000,
"user_id": 1000,
"contact_number": "NA",
"province": 0,
"location": "100000",
"total": 0,
"confirm_code": 1234,
"status": 0,
"created_at": "2020-03-18 22:07:25",
"updated_at": "2020-03-18 22:07:25"
},
{
"id": 4,
"invoice_id": 100000,
"user_id": 1000,
"contact_number": "NA",
"province": 0,
"location": "100000",
"total": 0,
"confirm_code": 1234,
"status": 0,
"created_at": "2020-03-18 22:10:40",
"updated_at": "2020-03-18 22:10:40"
},
{
"id": 5,
"invoice_id": 100000,
"user_id": 1000,
"contact_number": "NA",
"province": 0,
"location": "100000",
"total": 0,
"confirm_code": 1234,
"status": 0,
"created_at": "2020-03-18 22:12:29",
"updated_at": "2020-03-18 22:12:29"
}
],
"message": null
}
and my struct is,
struct Invoice: Codable {
let statusCode: Int
let data: [Datum]
let message: String?
enum CodingKeys: String, CodingKey {
case statusCode
case data, message
}
}
struct Datum: Codable {
let id, invoiceID, userID: Int
let contactNumber: String
let province: Int
let location: String
let total, confirmCode, status: Int
let createdAt, updatedAt: String
enum CodingKeys: String, CodingKey {
case id
case invoiceID
case userID
case contactNumber
case province, location, total
case confirmCode
case status
case createdAt
case updatedAt
}
}
and In View Controller,
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://xxxxx/api/invoices/\(1000)")!
var request = URLRequest(url: url)
request.httpMethod = "get"
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let jsonData = try JSONDecoder().decode([Invoice].self, from: data)
print(jsonData)
}
catch let jsonerr {
print("error serrializing error",jsonerr)
}
}
task.resume()
}
But Im keeping below error message,
error serrializing error typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
Please what Im missing here ! Any help will be much appreciated
The Codable struct will be like
struct Invoice: Codable {
let statusCode: Int
let data: [Datum]
let message: String?
enum CodingKeys: String, CodingKey {
case statusCode = "status_code"
case data, message
}
}
struct Datum: Codable {
let id, invoiceID, userID: Int
let contactNumber: String
let province: Int
let location: String
let total, confirmCode, status: Int
let createdAt, updatedAt: String
enum CodingKeys: String, CodingKey {
case id = "id"
case invoiceID = "invoice_id"
case userID = "user_id"
case contactNumber = "contact_number"
case province, location, total
case confirmCode = "confirm_code"
case status
case createdAt = "created_at"
case updatedAt = "updated_at"
}
}
And also use
let jsonData = try JSONDecoder().decode(Invoice.self, from: data)
instead of
let jsonData = try JSONDecoder().decode([Invoice].self, from: data)

How to get json response using alamofire in iOS Swift?

I have been trying to get json response from url using alamofire. Created model, apirouter and api client class.
its shows error
failure(Alamofire.AFError.responseSerializationFailed(reason:
Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error:
Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "variables", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"variables\", intValue: nil) (\"variables\").", underlyingError: nil)))))
Here is my postman json response:
[
{
"id": "00602c70-fc8a-11e9-ad1d-2abe2670111d",
"resourceType": "Task",
"name": "My Tasks",
"owner": null,
"query": {
"assigneeExpression": "${currentUser()}",
"taskVariables": [],
"processVariables": [],
"caseInstanceVariables": [],
"orQueries": []
},
"properties": {
"variables": [
{
"name": "loanAmount",
"label": "Loan Amount"
},
{
"name": "firstName",
"label": "First Name"
}
],
"color": "#555555",
"showUndefinedVariable": false,
"description": "Tasks assigned to me",
"refresh": false,
"priority": -10
}
}
]
My trying get values for id, name and properties -> variables -> name and label from json response.
Here is model class:
import Foundation
public struct Filter: Codable {
let id: String
let name: String
let properties: [variables]
}
public struct variables: Codable {
let name: String
let label: String
}
Here is code for alamofire :
private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:#escaping (AFResult<T>)->Void) -> DataRequest {
return AF.request(route)
.responseDecodable (decoder: decoder){ (response: AFDataResponse<T>) in
completion(response.result)
print("framework response::",response.result)
}
}
public static func getFilter(completion:#escaping (AFResult<[Filter]>)->Void) {
let jsonDecoder = JSONDecoder()
performRequest(route: APIRouter.getFilter, decoder: jsonDecoder, completion: completion)
}
Any help much appreciates pls...
your model class should be like the below.
import Foundation
public struct Filter: Codable {
let id: String
let name: String
let properties: Properties
}
public struct Properties: Codable {
let variables: [variables]
let color: String
let showUndefinedVariable: Bool
let description: String
let refresh: Bool
let priority: Int
}
public struct variables: Codable {
let name: String
let label: String
}
Did you try this one? This is what it should be
public struct Filter: Codable {
let id: String
let name: String
let properties: Property
}
public struct Property: Codable {
let variables: [Variable]
}
public struct Variable: Codable {
let name: String
let label: String
}
The error message you're getting is pretty clear: No value associated with key CodingKeys(stringValue: \"variables\"
You're attempting to decode the JSON into the Filter struct, but the JSON has no variables property. You could fix this by introducing a new Properties struct that will wrap the variables property, like this:
struct Filter: Codable {
let id: String
let name: String
let properties: Properties
}
struct Properties: Codable {
let variables: Variables
}
struct Variables: Codable {
let name: String
let label: String
}
Also, as you'll see in this snippet, it's convention to make the write the type names in CamelCase, so struct Variables instead of struct variables.

Error message saying that coding keys not found json

I am trying to decode an API call and I keep getting an error stating:
keyNotFound(CodingKeys(stringValue: "instruction", intValue: nil),
Swift.DecodingError.Context(codingPath: [], debugDescription: "No
value associated with key CodingKeys(stringValue: \"instruction\",
intValue: nil) (\"instruction\").", underlyingError: nil))
This is the json data
"resourceSets": [
{
"resources": [
{
"routeLegs": [
{
"itineraryItems": [
{
"compassDirection": "south",
"details": [
{
"compassDegrees": 182,
"endPathIndices": [
1
],
"maneuverType":
"DepartStart",
"mode": "Driving",
"names": [
"Infinite Loop"
],
"roadType": "Street",
"startPathIndices": [
0
]
}
],
"iconType": "Auto",
"instruction": {
"formattedText": "<Action>Depart</Action> <RoadName>Infinite Loop</RoadName> toward <Toward>Mariani Ave</Toward>",
"maneuverType": "DepartStart",
"text": "Depart Infinite Loop toward Mariani Ave"
},
Here is my data structs and coding keys
struct TruckRoute: Codable {
let resourceSets: [ResourceSet]
enum CodingKeys: String, CodingKey {
case resourceSets
}
}
// MARK: - ResourceSet
struct ResourceSet: Codable {
let resources: [Resource]
}
// MARK: - Resource
struct Resource: Codable {
let routeLegs: [RouteLeg]
enum CodingKeys: String, CodingKey {
case routeLegs
}
}
// MARK: - RouteLeg
struct RouteLeg: Codable {
let itineraryItems: [ItineraryItem]
enum CodingKeys: String, CodingKey {
case itineraryItems
}
}
// MARK: - ItineraryItem
struct ItineraryItem: Codable {
let instruction: Instruction
private enum CodingKeys: String, CodingKey {
case instruction
}
}
// MARK: - Instruction
struct Instruction: Codable {
let formattedText, maneuverType, text: String
private enum CodingKeys: String, CodingKey {
case formattedText, maneuverType, text
}
}
https://dev.virtualearth.net/REST/v1/Routes/Truck?wp.0=37.33233141,%20-122.0312186&wp.1=33.1956369,%20-117.3784666&key=AhLvBEtcGrKMDAIHHOhIhDm-aMM_dvGqstttp3wLfs8-J2A0UVBgN5bkzvaiZhj8

Resources