How to define list of dictionaries in a struct - json

I want to load JSON that contains a list of dictionary, for example
{error: false, "objects": [{"id": 1, "name": "cat"}, {"id": 2, "name": "dog"}, {"id": 3, "name": "fish"}]
How could this be defined in a
struct name: Codable, Identifiable {
}
to be used in JSONDecoder to decode the received data.
How can the struct be written to define this datatype

struct data: Codable {
let error: Bool
let objects: [dataObjects]
}
struct dataObjects: Codable {
let id: Int
let name: String
}

Related

How to decode an array contained in a dictionary directly using Swift JSON Decoder?

Suppose we have a json object like this:
{
"count": 2,
"users": [
{
"name": "tom",
"id": 123
},
{
"name": "cat",
"id": 456
}
]
}
and the User struct would be like:
struct User: Decodable {
let name: String
let id: Int
}
Obviously you can create another struct named Root to decode the json object using JSONDecoder:
struct Root: Decodable {
let count: Int,
let users: [User]
}
let root = try JSONDecoder().decode(Root.self, from: json)
let users = root.users
but actually Root is useless for me, the nested users is only what I concerned. So how can I decode only the users part into [User] without the needless Root struct?

Issues with Codable struct and Measuments<Unit>

Can't figure out how to save to JSON standard units of the Dimension class, I have a struct:
struct Item: Hashable, Identifiable, Codable {
var id: Int
var name: String
var price: Int
var unit: Measurement<Unit>
}
Xcode doesn't throw any errors so I'm assuming Measurement can be encoded? I can't really make it working and save a json, and how should my json data look like if I want to load the struct with a test json?
[
{
"id": 1,
"name": "Test",
"price": 195,
"unit": ???
}
]
The idea is that I operate with the standard Dimension class that has all units I need (kg/g/L/ml) instead of creating my own class and describe all units from scratch.
Is it possible to have a JSON with "unit": "kg" that then will match a standard UnitMass.kilogram automatically?
Thanks.
For me this actually works with this (simplified) example:
struct Item: Codable {
var name: String
var unit: Measurement<Unit>
}
let json =
"""
{
"name": "Test",
"unit": {
"value": 12,
"unit": {
"symbol": "ml"
}
}
}
""".data(using: .utf8)!
let item = try JSONDecoder().decode(Item.self, from: json)
yields the correct result. You can replace the unit symbol with anything you like (kg, g, ml, e.t.c)

How should I make the struct to get this JSON data in SwiftUI?

I am making an HTTP GET request and I want to save the JSON response that looks like this:
{
"code": 200,
"status": "success",
"patients": [
{
"_id": "5e77c7bbc7cbd30024f3eadb",
"name": "Bogdan Patient",
"username": "bogdanp",
"phone": "0732958473"
},
{
"_id": "5e77c982a2736a0024e895fa",
"name": "Robert Patient",
"username": "robertp",
"phone": "0739284756"
}
]
}
And here is my struct:
struct Doctor: Codable, Identifiable {
let id = UUID()
let patients: [Patients]
}
struct Patients: Codable {
let id: String
let name: String
let phone: String
}
As per your model, id is expected in the JSON whereas the keyname in the JSON is _id.
You can use CodingKeys to fix this:
struct Patients: Codable {
let id: String
let name: String
let phone: String
enum CodingKeys: String, CodingKey {
case id = "_id"
case name
case phone
}
}
CodingKeys creates a map between the keynames in your model and the keynames in the JSON response.
There are other reasons to use CodingKeys but for your current purpose this is enough.
Read More: Codable in Swift

How to create a Swift model for JSON

{"dataList":{"1547795650562": {
"c0a8007b-6759-111d-8167-59e8dabe0086": {
"recordDate": 1547795650562,
"resultValue": "160",
"vitalParameter": {
"uom": {
"code": "KG",
"name": "KG",
"id": "c0a8007b-6759-111d-8167-59e76204007f"
},
"resultType": {
"code": "VSRTNUMERIC",
"name": "Numeric",
"id": "20cf4756-40b0-4cc1-acb5-861765370a41"
},
"code": "29463-7",
"name": "Weight",
"id": "c0a8007b-6759-111d-8167-59e8dabe0086"
},
"id": "c0a8007b-6855-1d16-8168-5fd18fa301b7"
}}
}}
getting 1547795650562 and c0a8007b-6759-111d-8167-59e8dabe0086 as class names. But I dont want like this;
class DataList : NSObject, NSCoding{
var 1547795650562 : 1547795650562!
}
class 1547795650562 : NSObject, NSCoding{
var c0a8007b6759111d816759e8dabe0086 : VitalParameter!
}
But the problem here is, 1547795650562 and c0a8007b-6759-111d-8167-59e8dabe0086 cannot be hard coded because they may change.
c0a8007b-6759-111d-8167-59e8dabe0086 is dynamic id and 1547795650562 is recordDate. Inner object is repetitive.
But I have to map as the keys are of recordDate and id respectively.
Try using Codable instead of NSCoding to parse your JSON data.
Models:
struct Root: Codable {
let dataList: [String:[String:Record]]
}
struct Record: Codable {
let recordDate: Int
let resultValue: String
let vitalParameter: VitalParameter
let id: String
}
struct VitalParameter: Codable {
let uom, resultType: ResultType
let code, name, id: String
}
struct ResultType: Codable {
let code, name, id: String
}
Parse the JSON data using above models like,
do {
let response = try JSONDecoder().decode(Root.self, from: data)
print(response)
} catch {
print(error)
}
Note: You can use https://app.quicktype.io to get the models from your JSON instantly. Make the changes as per your requirement and you're good to go.

Generics on SWIFT Struct

Im trying to make generic structs on SWIFT to work with JSON and Codable, but i dont know if it is possible.
Without generics, it works.
struct apiContainer: Decodable {
let meta: Meta
let result: [Client]
}
I have a struct named "Client" and I would like to have other structs, for example: owner, plant and so on.
All JSON response has to go to apiContainer. It has Meta and [Client].
My goal is to make [Client] being [T] so i can pass any struct to apiContainer.
Bellow is a piece of a code that im trying on the playground.
Questions:
Is it possible?
How can I make it (both on struct and the json.decode line)
import PlaygroundSupport
import UIKit
import Foundation
struct Client: Decodable {
let name: String
let postal_code: String
let city: String
}
struct Meta: Decodable {
let sucess: String
let value: String
}
struct apiContainer<T>: Decodable {
let meta: Meta
let result: [T]
}
let json = """
{
"meta": {
"sucess": "yes",
"value": "123"
},
"result": [
{
"name": "Name 1",
"postal_code": "PC1",
"city": "City 1",
"address": "01 Street"
},
{
"name": "Name 2",
"postal_code": "PC2",
"city": "City 2",
"address": "02 Street"
}
]
}
""".data(using: .utf8)!
let converted = try JSONDecoder().decode(apiContainer.self, from: json)
print(converted.result)
print(converted.meta)
struct apiContainer<T>: Decodable
Should be
struct ApiContainer<T: Decodable>: Decodable
And
try JSONDecoder().decode(apiContainer.self, from: json)
Should be
try JSONDecoder().decode(ApiContainer<Client>.self, from: json)
And voilĂ ! It works.