Here is my JSON
{
"myItems": {
"item1name": [{
"url": "google.com",
"isMobile": true,
"webIdString": "572392"
}, {
"url": "hulu.com",
"isMobile": false,
"webIdString": "sad1228"
}],
"item2name": [{
"url": "apple.com",
"isMobile": true,
"webIdString": "dsy38ds"
}, {
"url": "Facebook.com",
"isMobile": true,
"webIdString": "326dsigd1"
}, {
"url": "YouTube.com",
"isMobile": true,
"webIdString": "sd3dsg4k"
}]
}
}
The json can have multiple items (such as item1name, item2name, item3name,...) and each item can have multiple objects (the example has 2 objects for the first item and 3 objects for the second item).
Here is the structure I want it saved to (incomplete):
struct ServerResponse: Decodable {
let items: [MyItem]?
}
struct MyItem: Decodable {
let itemName: String?
let url: String?
let isMobile: Bool?
let webIdString: String?
}
In the example above, it would mean that the items list should have five MyItem objects. For example, these would be the MyItem objects:
#1:
itemName: item1name,
url: google.com,
isMobile: true,
webIdString: 572392
#2:
itemName: item1name,
url: hulu.com,
isMobile: false,
webIdString: sad1228
#3:
itemName: item2name,
url: apple.com,
isMobile: true,
webIdString: dsy38ds
#4:
itemName: item2name,
url: Facebook.com,
isMobile: true,
webIdString: 326dsigd1
#5:
itemName: item2name,
url: YouTube.com,
isMobile: true,
webIdString: sd3dsg4k
What would be the best way for me to do this using Decodable? Any help would be appreciated. I think this may be similar to this problem: How to decode a nested JSON struct with Swift Decodable protocol?
Use below code to decode nested JSON for your requirement:
import Foundation
// MARK: - Websites
struct Websites: Codable {
var myItems: MyItems
}
// MARK: - MyItems
struct MyItems: Codable {
var item1Name, item2Name: [ItemName]
enum CodingKeys: String, CodingKey {
case item1Name = "item1name"
case item2Name = "item2name"
}
}
// MARK: - ItemName
struct ItemName: Codable {
var url: String
var isMobile: Bool
var webIDString: String
enum CodingKeys: String, CodingKey {
case url, isMobile
case webIDString = "webIdString"
}
}
NOTE: change the name of the variables according to your need.
EDIT
If you're still facing issue, use this app to convert your JSON to Struct:
Quick Type
Here is the structure you are after:
struct Websites: Decodable {
let items: [Item]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Key.self)
items = try container.decode([String: [Item]].self, forKey: .myItems).values.flatMap { $0 }
}
private enum Key: String, CodingKey {
case myItems
}
}
struct Item: Decodable {
let url: String
let isMobile: Bool
let webIdString: String
}
Related
I have a Json in which there is the possibility that a few keys can be missing
Full JSON looks like this
{
"data": "some text",
"id": "3213",
"title": "title",
"description": "description",
"customObj1": [{
"id": "2423",
"count": 35
........
.......
}]
"customObj2": [{
"number": "2423",
"name": "john"
........
.......
}]
"customObj3": [{
"like": "2423",
"Other": 9
........
.......
}]
}
the custom object (1,2,3) may or may not be available in JSON, How can I write the model in swift using codable and struct?
here is how the model (dummy) look like
// MARK: - Response
struct Response: Codable {
let data, id, title, ResponseDescription: String
let customObj1: [CustomObj1]
let customObj2: [CustomObj2]
let customObj3: [CustomObj3]
enum CodingKeys: String, CodingKey {
case data, id, title
case ResponseDescription = "description"
case customObj1, customObj2, customObj3
}
}
// MARK: - CustomObj1
struct CustomObj1: Codable {
let id: String
let count: Int
}
// MARK: - CustomObj2
struct CustomObj2: Codable {
let number, name: String
}
// MARK: - CustomObj3
struct CustomObj3: Codable {
let like: String
let other: Int
enum CodingKeys: String, CodingKey {
case like
case other = "Other"
}
}
I have tried using decode init but need help
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if (values.contains(. customObj1)) {
// here I need help }
else {
self.category = nil
}
}
}
I try to Post Json with alamofire, which I can, but I need a value that I get from the result of that successful API post. how do I get value from post method JSON in swift? i use Alamofire to make things simple.
{
"phoneNum": "+1234566869",
"phoneNumTarget": "+2345687960",
"id": "79999000"
}
so this is the body parameter for my Post JSON,
and this is the result of a successful post JSON
{
"data": {
"orderId": "79999000",
"uniquesRoomId": 12341414,
"users": [
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "BuzzLightyear"
},
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "General Zurg"
}
],
"chat_name": "user2"
},
"message": "room has been successfully created",
"success": true
}
Now I want to retrieve all the value that I get from that post Json method, how do I do it? do I need to make a struct first like when I want to make get method request for JSON?
*update question
let data : [DataClass] = [ ]
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case.success :
self.data = response
break
i try for this and it getting some error
You need to parse this response through Decodable confirmed structs
import Foundation
// MARK: - User
struct User: Codable {
let data: DataClass
let message: String
let success: Bool
}
// MARK: - DataClass
struct DataClass: Codable {
let orderID: String
let uniquesRoomID: Int
let users: [UserElement]
let chatName: String
enum CodingKeys: String, CodingKey {
case orderID = "orderId"
case uniquesRoomID = "uniquesRoomId"
case users
case chatName = "chat_name"
}
}
// MARK: - UserElement
struct UserElement: Codable {
let avatarURL: String
let phoneNumber, fullname: String
enum CodingKeys: String, CodingKey {
case avatarURL = "avatar_url"
case phoneNumber = "phone_number"
case fullname
}
}
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case .success(let data) :
let user = try? JSONDecoder().decode(User.self, from: data)
Okay, so I am stuck at decoding the last item of this particular json by this the model, "payload" is always nil, Inside this "payload" object I can make my own json structure, I am able to decode the "text" but when it comes to the last item which is "payload", it is not working and is always nil.
I am not using any third-party library.
My Model Class.
struct DailougeFlowModel : Decodable {
// private enum CodingKeys : String, CodingKey {
// case responseId = "responseId"
// case queryResult = "queryResult"
// }
let responseId : String?
let queryResult : QueryResult?
}
struct QueryResult: Decodable {
// private enum CodingKeys : String, CodingKey {
// case fulfillmentText = "fulfillmentText"
// case fulfillmentMessages = "fulfillmentMessages"
// }
let fulfillmentText : String?
let fulfillmentMessages : [FulfillmentMessages]?
}
struct FulfillmentMessages: Decodable {
let text : TextModel?
let payLoad : Questions?
}
struct TextModel: Decodable {
let text : [String]?
}
struct Questions : Decodable{
let questions : [String]?
}
This json is what I am getting from the dailogeflow(V2). I am integrating a chatbot in the application.
{
"responseId": "2b879f78-cc05-4735-a7e8-067fdb53a81d-f6406966",
"queryResult": {
"fulfillmentMessages": [
{
"text": {
"text": [
"Text Here"
]
}
},
{
"text": {
"text": [
"Another Reply For Hi"
]
}
},
{
"payload": {
"questions": [
"Question One",
"Question Two",
"Question Three",
"Question Four"
]
}
}
]
}
}
Specify the inner model names as it is in the json response, if you want to specify your own model name then you would need to set an enum in each model just like the first model 'ResponseModel'
// MARK: - ResponseModel
struct ResponseModel: Codable {
let responseID: String
let queryResult: QueryResult
enum CodingKeys: String, CodingKey {
case responseID = "responseId"
case queryResult
}
}
// MARK: - QueryResult
struct QueryResult: Codable {
let fulfillmentMessages: [FulfillmentMessage]
}
// MARK: - FulfillmentMessage
struct FulfillmentMessage: Codable {
let text: Text?
let payload: Payload?
}
// MARK: - Payload
struct Payload: Codable {
let questions: [String]
}
// MARK: - Text
struct Text: Codable {
let text: [String]
}
I'm trying to decode this json but certain variables are nil. Most of these seem to be okay it's just a few that are not working properly. I don't have much experience with swift so I'm kind of at a loss of what to try next.
mycode:
struct Attr : Decodable {
let page: String?
let perpage: String?
let totalpages: String?
let total: String?
}
struct Images : Decodable {
let text: String?
let size: String?
}
struct Artist : Decodable {
let name: String?
let mbid: String?
let url: String?
}
struct Streamable : Decodable {
let text: String?
let fulltrack: String?
}
struct Track : Decodable {
let name: String?
let duration: String?
let playcount: String?
let listeners: String?
let mbid: String?
let url: String?
let streamable: Streamable?
let artist: Artist?
let images: [Images]?
}
struct Tracks : Decodable {
let track:[Track]?
}
struct Container : Decodable {
let tracks: Tracks?
let attr: Attr?
}
json:
{
"tracks": {
"track": [
{
"name": "bad guy",
"duration": "0",
"playcount": "870682",
"listeners": "125811",
"mbid": "",
"url": "https://www.last.fm/music/Billie+Eilish/_/bad+guy",
"streamable": {
"#text": "0",
"fulltrack": "0"
},
"artist": {
"name": "Billie Eilish",
"mbid": "",
"url": "https://www.last.fm/music/Billie+Eilish"
},
"image": [
{
"#text": "https://lastfm-img2.akamaized.net/i/u/34s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "small"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/64s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "medium"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/174s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "large"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/300x300/88d7c302d28832b53bc9592ccb55306b.png",
"size": "extralarge"
}
]
},
...
images should contain an array of Images instead of nil, the majority of the other variables seem to be okay though
This is because when dealing with decodable the keys used in your serialized data format have to match the property names; In your case, the Image type contains text and size properties but the json contains #text and size (text =/= #text); That's also applicable for the type name Images not image.
However, citing from Encoding and Decoding Custom Types:
If the keys used in your serialized data format don't match the
property names from your data type, provide alternative keys by
specifying String as the raw-value type for the CodingKeys
enumeration.
Add CodingKeys as:
struct Images : Decodable {
let text: String?
let size: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case size
}
}
Tip: it is useful to use try/catch when facing an error while decoding your data:
do {
let result = try JSONDecoder().decode(Images.self, from: data)
} catch {
print(error.localizedDescription)
}
At this point it would print the error which might helpful to understand the issue most of the time.
Add CodingKey enum to map fields with # in the name
struct Images : Decodable {
let text: String?
let size: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case size
}
}
struct Streamable : Decodable {
let text: String?
let fulltrack: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case fulltrack
}
}
You also have an error in your Trackstruct, change images to image (or use CodingKey mapping there to). For more on decoding json see Apple's doc
So I'm trying to parse JSON that looks something like this using Codable in Swift.
{
"abilities": [
{
"ability": {
"name": "chlorophyll",
"url": "https://pokeapi.co/api/v2/ability/34/"
},
"is_hidden": true,
"slot": 3
},
{
"ability": {
"name": "overgrow",
"url": "https://pokeapi.co/api/v2/ability/65/"
},
"is_hidden": false,
"slot": 1
}
],
"name": "SomeRandomName"
}
Now it gets confusing when you're trying to get nested data. Now I'm trying to get the name, which is easy. I'm also trying to get the ability name, this is where its gets complicated for me. After some research this is what I came up with.
class Pokemon: Codable {
struct Ability: Codable {
var isHidden: Bool
struct AbilityObject: Codable {
var name: String
var url: String
}
var ability: AbilityObject
private enum CodingKeys: String, CodingKey {
case isHidden = "is_hidden"
case ability
}
}
var name: String
var abilities: [Ability]
}
Now is there any better way in doing this, or am I stuck doing it like this.
Grab your JSON response and dump it in this site.
It'll generate these structs without Codable. Add Codable so they look like this:
struct Pokemon: Codable {
let abilities: [AbilityElement]
let name: String
struct AbilityElement: Codable {
let ability: Ability
let isHidden: Bool
let slot: Int
struct Ability: Codable {
let name: String
let url: String
}
}
}
For keys with snake_case, you can just declare a JSONDecoder and specify the keyDecodingStrategy as .convertFromSnakeCase. No need to muck around with coding keys if you're just converting from snake case. You only need them if you're renaming keys.
If you have other situations where you need to create custom coding keys for your responses or alter key names, this page should prove helpful.
You can dump this in a playground and play around with it:
let jsonResponse = """
{
"abilities": [
{
"ability": {
"name": "chlorophyll",
"url": "https://pokeapi.co/api/v2/ability/34/"
},
"is_hidden": true,
"slot": 3
},
{
"ability": {
"name": "overgrow",
"url": "https://pokeapi.co/api/v2/ability/65/"
},
"is_hidden": false,
"slot": 1
}
],
"name": "SomeRandomName"
}
"""
struct Pokemon: Codable {
let abilities: [AbilityElement]
let name: String
struct AbilityElement: Codable {
let ability: Ability
let isHidden: Bool
let slot: Int
struct Ability: Codable {
let name: String
let url: String
}
}
}
var pokemon: Pokemon?
do {
let jsonDecoder = JSONDecoder()
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
if let data = jsonResponse.data(using: .utf8) {
pokemon = try jsonDecoder.decode(Pokemon.self, from: data)
}
} catch {
print("Something went horribly wrong:", error.localizedDescription)
}
print(pokemon)