structure for Decodable JSON - json
I am trying to put the following API link into a Decodable JSON in Swift
Link Here
Below is the code to map the link:
import Foundation
struct SelectedCompany: Decodable {
let LastTradePrice: Double
let ListedCompanyID: String
let ListedCompanyName: String
let MarketTotalOrdersByOrder: Int
let MarketTotalOrdersByPrice: Int
let MarketTotalSharesByOrder: Int
let MarketTotalSharesByPrice: Int
let NumberOfTrades: Int
let Value: Int
let Volume: Int
let MarketAskOrdersByOrder: [Order]
let MarketAskOrdersByPrice: [Order]
let MarketBidOrdersByOrder: [Order]
let MarketBidOrdersByPrice: [Order]
let VWAP: Int
}
struct Order: Decodable {
let Price: Double
let Shares: Int
}
Any idea why is not mapping correctly? When I try to run it in the simulator, I am getting the below error
dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
Thanks
Post Edit:
The error comes when I run the below function in a separate class called Service:
class Service {
static func getSpecificCompany(companyID: String, table: UITableView, completion: #escaping (SelectedCompany) -> ()) {
let link = "https://www.adx.ae/en/_vti_bin/ADX/svc/trading.svc/ListedCompanyOrderBook?listedCompanyID=\(companyID)"
guard let url = URL(string: link) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let resultData = data else { return }
do {
let resultCompany = try JSONDecoder().decode(SelectedCompany.self, from: resultData)
DispatchQueue.main.async {
completion(resultCompany)
table.reloadData()
}
} catch {
print(error)
}
}.resume()
}
}
In the ViewController class, the above function will be as follows:
class SomeViewController: UIViewController {
#IBOutlet weak var myTable: UITableView!
var selectedCompany:[SelectedCompany]?
var companyID = String()
override func viewDidLoad() {
super.viewDidLoad()
Service.getSpecificCompany(companyID: companyID, table: myTable) { (company) in
self.selectedCompany = company
}
}
}
The only problem with your structs is the presence of this sort of thing in the JSON:
{"Price":null,"Shares":null}
To cope with that, you need to rewrite your Order struct to allow for null:
struct Order: Decodable {
let Price: Double?
let Shares: Int?
}
As soon as I do that, I can successfully decode the JSON you showed using your SelectedCompany and Order.
Here is playground code that tests (successfully):
let json = """
{"LastTradePrice":3.87,"ListedCompanyID":"ADIB","ListedCompanyName":"Abu Dhabi Islamic Bank","MarketAskOrdersByOrder":[{
"Price":3.87,"Shares":100000},{
"Price":3.88,"Shares":100000},{
"Price":3.88,"Shares":6000},{
"Price":3.89,"Shares":100000},{
"Price":3.9,"Shares":30000},{
"Price":3.9,"Shares":100000},{
"Price":3.98,"Shares":99800},{
"Price":3.98,"Shares":10000},{
"Price":3.99,"Shares":75000},{
"Price":3.99,"Shares":285018},{
"Price":4,"Shares":100000},{
"Price":4,"Shares":100000},{
"Price":4,"Shares":10000},{
"Price":4,"Shares":6336},{
"Price":4,"Shares":100000},{
"Price":4.09,"Shares":5000},{
"Price":4.1,"Shares":50000},{
"Price":4.11,"Shares":5000},{
"Price":4.13,"Shares":28894},{
"Price":4.13,"Shares":25000}],"MarketAskOrdersByPrice":[{
"Price":3.87,"Shares":100000},{
"Price":3.88,"Shares":106000},{
"Price":3.89,"Shares":100000},{
"Price":3.9,"Shares":130000},{
"Price":3.98,"Shares":109800},{
"Price":3.99,"Shares":360018},{
"Price":4,"Shares":316336},{
"Price":4.09,"Shares":5000},{
"Price":4.1,"Shares":50000},{
"Price":4.11,"Shares":5000},{
"Price":4.13,"Shares":53894},{
"Price":4.14,"Shares":193000},{
"Price":4.15,"Shares":85000},{
"Price":4.2,"Shares":127211},{
"Price":4.25,"Shares":250000},{
"Price":4.26,"Shares":10000}],"MarketBidOrdersByOrder":[{
"Price":3.85,"Shares":5349},{
"Price":3.85,"Shares":200000},{
"Price":3.84,"Shares":70000},{
"Price":3.84,"Shares":300000},{
"Price":3.83,"Shares":75000},{
"Price":3.81,"Shares":28000},{
"Price":3.8,"Shares":700000},{
"Price":3.79,"Shares":100000},{
"Price":3.79,"Shares":10000},{
"Price":3.72,"Shares":50000},{
"Price":3.68,"Shares":100000},{
"Price":3.67,"Shares":15000},{
"Price":3.67,"Shares":25000},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null}],"MarketBidOrdersByPrice":[{
"Price":3.85,"Shares":205349},{
"Price":3.84,"Shares":370000},{
"Price":3.83,"Shares":75000},{
"Price":3.81,"Shares":28000},{
"Price":3.8,"Shares":700000},{
"Price":3.79,"Shares":110000},{
"Price":3.72,"Shares":50000},{
"Price":3.68,"Shares":100000},{
"Price":3.67,"Shares":40000},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null},{
"Price":null,"Shares":null}],"MarketTotalOrdersByOrder":28,"MarketTotalOrdersByPrice":16,"MarketTotalSharesByOrder":1678349,"MarketTotalSharesByPrice":1678349,"NumberOfTrades":41,"VWAP":0,"Value":7159043,"Volume":1863558}
"""
let jsondata = json.data(using: .utf8)
struct SelectedCompany: Decodable {
let LastTradePrice: Double
let ListedCompanyID: String
let ListedCompanyName: String
let MarketTotalOrdersByOrder: Int
let MarketTotalOrdersByPrice: Int
let MarketTotalSharesByOrder: Int
let MarketTotalSharesByPrice: Int
let NumberOfTrades: Int
let Value: Int
let Volume: Int
let MarketAskOrdersByOrder: [Order]
let MarketAskOrdersByPrice: [Order]
let MarketBidOrdersByOrder: [Order]
let MarketBidOrdersByPrice: [Order]
let VWAP: Int
}
struct Order: Decodable {
let Price: Double?
let Shares: Int?
}
do {
let result = try JSONDecoder().decode(SelectedCompany.self, from: jsondata!)
print(result) // works fine
} catch {
print(error) // no error
}
Related
How to store data from json and from CoreData? SwiftUI
I study SwiftUI and I have an interesting task. I need to get data from a site and store it in CoreData. Then, I need to get them from CoreData and show it in my View if I don't have internet. I created my data model: struct User: Codable, Identifiable, Hashable { struct Friend: Codable, Identifiable, Hashable { let id: String let name: String } let id: String let name: String let isActive: Bool let age: Int let company: String let email: String let address: String let about: String let registered: Date let friends: [Friend] } This is how I get the data form the site: struct ContentView: View { #Environment(\.managedObjectContext) private var viewContext //#FetchRequest(entity: CDUser.entity(), sortDescriptors: []) var users: FetchedResults<CDUser> #State private var users = [User]() // some code // ............. func loadData() { guard let url = URL(string: "https://****************.json") else { return } let request = URLRequest(url: url) URLSession.shared.dataTask(with: request) { data, response, error in if let data = data { do { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 let decoded = try decoder.decode([User].self, from: data) DispatchQueue.main.async { self.users = decoded return } } catch { print("Decode error:", error) } } print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")") }.resume() } } So now I don't know how to store a variable which will contains data from the site and from CoreData when it needed. Can anyone give some advice? User entity Friend entity
Cannot assign value of type 'MRData' to type '[F1Data]' when trying to parse JSON
I have been wrestling with this for a while. I am trying to parse a JSON Api into a UITableview. The url is Formula One API . I am using Codable rather than third party pods. Thought this might cut down on the amount of code. Although, as the API is not that straight forward it is hard to extract what I want. Basically, I want to list the current standing for drivers for a given year. In url and code I have given I have chosen 1999 as an example. I have been researching on Stackoverflow but each solution is very specific to a particular problem and I can't seem to relate to my issue. Below is the code I have. struct MRData: Codable { let xmlns: String? let series: String? let url: String? let limit, offset, total: String? let standingsTable: StandingsTable enum CodingKeys: String, CodingKey { case xmlns, series, url, limit, offset, total case standingsTable = "StandingsTable" } } struct StandingsTable: Codable { let season: String? let standingsLists: [StandingsList] enum CodingKeys: String, CodingKey { case season case standingsLists = "StandingsLists" } } struct StandingsList: Codable { let season, round: String? let driverStandings: [DriverStanding] enum CodingKeys: String, CodingKey { case season, round case driverStandings = "DriverStandings" } } struct DriverStanding: Codable { let position, positionText, points, wins: String? let driver: Driver let constructors: [Constructor] enum CodingKeys: String, CodingKey { case position, positionText, points, wins case driver = "Driver" case constructors = "Constructors" } } struct Constructor: Codable { let constructorId: String? let url: String? let name: String? let nationality: String? } struct Driver: Codable { let driverId: String? let url: String? let givenName, familyName, dateOfBirth, nationality: String? } class f1TableViewController: UITableViewController { var champions: [F1Data] = [] override func viewDidLoad() { super.viewDidLoad() // let jsonUrlString = "https://api.letsbuildthatapp.com/jsondecodable/website_description" navigationController?.navigationBar.prefersLargeTitles = true navigationItem.title = "Champion Drivers" fetchJSON() } private func fetchJSON(){ let jsonUrlString = "https://ergast.com/api/f1/1999/driverstandings.json" guard let url = URL(string: jsonUrlString) else { return } URLSession.shared.dataTask(with: url) { (data, response, err) in DispatchQueue.main.async { if let err = err { print("Failed to get data from url:", err) return } guard let data = data else { return } do { let decoder = JSONDecoder() // Swift 4.1 decoder.keyDecodingStrategy = .convertFromSnakeCase self.champions = try decoder.decode(MRData.self, from: data) self.tableView.reloadData() //let season = f1Data.mrData.standingsTable.season // let firstDriver = f1Data.mrData.standingsTable.standingsLists[0].driverStandings // for driver in firstDriver { // // print("\(driver.driver.givenName) \(driver.driver.familyName)") // } //print(season) } catch { print(error) } } }.resume() } // Uncomment the following line to preserve selection between presentations // self.clearsSelectionOnViewWillAppear = false // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem // MARK: - Table view data source override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return champions.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellId") let champion = champions[indexPath.row] let driverName = champion.mrData.standingsTable.standingsLists[0].driverStandings for driver in driverName { cell.textLabel?.text = driver.driver.familyName } //cell.textLabel?.text = //cell.detailTextLabel?.text = String(course.numberOfLessons) return cell } } Now I realize that the error is in the do catch block. do { let decoder = JSONDecoder() // Swift 4.1 decoder.keyDecodingStrategy = .convertFromSnakeCase self.champions = try decoder.decode(MRData.self, from: data) self.tableView.reloadData() and that the array F1Data cannot be a dictionary of MRData. So if I change it to the following self.champions = try decoder.decode([F1Data].self, from: data) the I get another error which is debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil)). Any help would be appreciated with this.
As Vadian correctly said that you need to decode at the root of your object. I briefly watched this video and the penny dropped! Assign the decoder to a variable and add to decode the complete structure starting at the root object. guard let data = data else { return } do { let decoder = JSONDecoder() // Swift 4.1 decoder.keyDecodingStrategy = .convertFromSnakeCase let firstDriver = try decoder.decode(F1Data.self, from: data) self.champions = firstDriver.mrData.standingsTable.standingsLists[0].driverStandings self.tableView.reloadData()
URLSession Type Mismatch Error
I'm getting an Type Mismatch error when trying to parse json with Swift jSon Decoder. I just can't find a way to parse it normally. The Error: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "itemArr", intValue: nil), CodingKeys(stringValue: "price", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil)) The Decoder Code: func getDealDetails(id : String ,completion : #escaping ()->()) { let jsonUrl = "https://androidtest.inmanage.com/api/1.0/android/getDeal_\(id).txt" guard let url = URL(string: jsonUrl) else { return } URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data else { return } do { let deal = try JSONDecoder().decode(ResultDetails.self, from: data) AppManager.shared.dealToShow = deal.data.itemArr }catch { print("There's an error: \(error)") } completion() }.resume() } } And The Classes: First: class ResultDetails : Decodable { let data : DataDetails init(data : DataDetails) { self.data = data } } Second: class DataDetails : Decodable { let itemArr: ItemArr init(itemArr: ItemArr) { self.itemArr = itemArr } } And Third: class ItemArr : Decodable { let id, title, price, description: String let image: String let optionsToShow: Int let gps: Gps let website, phone: String init(id: String, title: String, price: String, description: String, image: String, optionsToShow: Int, gps: Gps, website: String, phone: String) { self.id = id self.title = title self.price = price self.description = description self.image = image self.optionsToShow = optionsToShow self.gps = gps self.website = website self.phone = phone } I think I tried everything for the last 6 hours to fix it, please help! EDIT: I put a wrong third class. now it's the right one
The error message is wrong. According to the JSON link and your classes it's supposed to be CodingKeys(stringValue: "price", intValue: nil)], debugDescription: Expected to decode Int but found a string/data instead., However it's going to tell you exactly what's wrong: The value for key price is a String rather than an Int. You have to read the JSON carefully. The format is very simple. For example everything in double quotes is String, there is no exception. Your data structure is too complicated. Use structs and drop the initializers. By the way there is a typo ItemsArr vs. ItemArr and there is no key orderNum. The key image can be decoded as URL. This is sufficient struct ResultDetails : Decodable { let data : DataDetails } struct DataDetails : Decodable { let itemArr: ItemArr } struct ItemArr : Decodable { let id, title: String let price: String let image: URL // let orderNum: Int } Specify the CodingKeys only if you want to map the keys. In your case you can even omit the CodingKeys, use theconvertFromSnakeCase strategy instead. decoder.keyDecodingStrategy = .convertFromSnakeCase
Yes you have an error let price: Int should be let price: String because it string in Json "price": "896" -- > String Example for Int "optionsToShow":1 --> this is Int Here is complete code you can use import Foundation struct ResultDetails: Codable { let data: DataDetails } struct DataDetails: Codable { let itemArr: ItemArr } struct ItemArr: Codable { let id, title, price, description: String let image: String let optionsToShow: Int let gps: Gps let website, phone: String } struct Gps: Codable { let lat, lon: String } // MARK: Convenience initializers extension ResultDetails { init(data: Data) throws { self = try JSONDecoder().decode(ResultDetails.self, from: data) } init(_ json: String, using encoding: String.Encoding = .utf8) throws { guard let data = json.data(using: encoding) else { throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil) } try self.init(data: data) } func jsonData() throws -> Data { return try JSONEncoder().encode(self) } func jsonString(encoding: String.Encoding = .utf8) throws -> String? { return String(data: try self.jsonData(), encoding: encoding) } }
debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil)
I want to load an online json file into my application, but I am running into this error: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil)) I have looked on stackoverflow but other sollutions didn't help to solve mine. My JSON: { "copyright" : "NHL and the NHL Shield are registered trademarks of the National Hockey League. NHL and NHL team marks are the property of the NHL and its teams. © NHL 2022. All Rights Reserved.", "totalItems" : 0, "totalEvents" : 0, "totalGames" : 0, "totalMatches" : 0, "metaData" : { "timeStamp" : "20220813_172145" }, "wait" : 10, "dates" : [ ] } My datamodel: import Foundation struct Initial: Codable { let copyright: String let totalItems: Int let totalEvents: Int let totalGames: Int let totalMatches: Int let wait: Int let dates: [Dates] } struct Dates: Codable { let date: String let totalItems: Int let totalEvents: Int let totalGames: Int let totalMatches: Int let games: [Game] } struct Game: Codable { let gamePk: Int let link: String let gameType: String let season: String let gameDate: String let status: Status let teams: Team let venue: Venue let content: Content } struct Status: Codable { let abstractGameState: String let codedGameState: Int let detailedState: String let statusCode: Int let startTimeTBD: Bool } struct Team: Codable { let away: Away let home: Home } struct Away: Codable { let leagueRecord: LeagueRecord let score: Int let team: TeamInfo } struct Home: Codable { let leagueRecord: LeagueRecord let score: Int let team: TeamInfo } struct LeagueRecord: Codable { let wins: Int let losses: Int let type: String } struct TeamInfo: Codable { let id: Int let name: String let link: String } struct Venue: Codable { let name: String let link: String } struct Content: Codable { let link: String } and here is my viewcontroller import UIKit class TodaysGamesTableViewController: UITableViewController { var todaysGamesURL: URL = URL(string: "https://statsapi.web.nhl.com/api/v1/schedule")! var gameData: [Dates] = [] let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) override func viewDidLoad() { super.viewDidLoad() loadTodaysGames() } func loadTodaysGames(){ print("load Games") view.addSubview(activityIndicator) activityIndicator.frame = view.bounds activityIndicator.startAnimating() let todaysGamesDatatask = URLSession.shared.dataTask(with: todaysGamesURL, completionHandler: dataLoaded) todaysGamesDatatask.resume() } func dataLoaded(data:Data?,response:URLResponse?,error:Error?){ if let detailData = data{ print("detaildata", detailData) let decoder = JSONDecoder() do { let jsondata = try decoder.decode([Dates].self, from: detailData) gameData = jsondata //Hier .instantie wil doen krijg ik ook een error DispatchQueue.main.async{ self.tableView.reloadData() } }catch let error{ print(error) } }else{ print(error!) } }
Please learn to understand the decoding error messages, they are very descriptive. The error says you are going to decode an array but the actual object is a dictionary (the target struct). First take a look at the beginning of the JSON { "copyright" : "NHL and the NHL Shield are registered trademarks of the National Hockey League. NHL and NHL team marks are the property of the NHL and its teams. © NHL 2018. All Rights Reserved.", "totalItems" : 2, "totalEvents" : 0, "totalGames" : 2, "totalMatches" : 0, "wait" : 10, "dates" : [ { "date" : "2018-05-04", It starts with a { which is a dictionary (an array is [) but you want to decode an array ([Dates]), that's the type mismatch the error message is referring to. But this is only half the solution. After changing the line to try decoder.decode(Dates.self you will get another error that there is no value for key copyright. Look again at the JSON and compare the keys with the struct members. The struct whose members match the JSON keys is Initial and you have to get the dates array to populate gameData. let jsondata = try decoder.decode(Initial.self, from: detailData) gameData = jsondata.dates
The JSON is represented by your Initial struct, not an array of Dates. Change: let jsondata = try decoder.decode([Dates].self, from: detailData) to: let jsondata = try decoder.decode(Initial.self, from: detailData)
Correct Answer is done previously from my two friends but you have to do it better i will provide solution for you to make code more clean and will give you array of Dates here is your model with codable import Foundation struct Initial: Codable { let copyright: String let totalItems: Int let totalEvents: Int let totalGames: Int let totalMatches: Int let wait: Int let dates: [Dates] } struct Dates: Codable { let date: String let totalItems: Int let totalEvents: Int let totalGames: Int let totalMatches: Int let games: [Game] } struct Game: Codable { let gamePk: Int let link: String let gameType: String let season: String let gameDate: String let status: Status let teams: Team let venue: Venue let content: Content } struct Status: Codable { let abstractGameState: String let codedGameState: Int let detailedState: String let statusCode: Int let startTimeTBD: Bool } struct Team: Codable { let away: Away let home: Home } struct Away: Codable { let leagueRecord: LeagueRecord let score: Int let team: TeamInfo } struct Home: Codable { let leagueRecord: LeagueRecord let score: Int let team: TeamInfo } struct LeagueRecord: Codable { let wins: Int let losses: Int let type: String } struct TeamInfo: Codable { let id: Int let name: String let link: String } struct Venue: Codable { let name: String let link: String } struct Content: Codable { let link: String } // MARK: Convenience initializers extension Initial { init(data: Data) throws { self = try JSONDecoder().decode(Initial.self, from: data) } } And Here is Controller Will make solution more easy class ViewController: UIViewController { var todaysGamesURL: URL = URL(string: "https://statsapi.web.nhl.com/api/v1/schedule")! var gameData: Initial? let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) override func viewDidLoad() { super.viewDidLoad() self.loadTodaysGames() } func loadTodaysGames(){ print("load Games") let todaysGamesDatatask = URLSession.shared.dataTask(with: todaysGamesURL, completionHandler: dataLoaded) todaysGamesDatatask.resume() } func dataLoaded(data:Data?,response:URLResponse?,error:Error?){ if let detailData = data { if let inital = try? Initial.init(data: detailData){ print(inital.dates) }else{ // print("Initial") } }else{ print(error!) } } }
Parsing JSON with Swift 4 Decodable
I have been getting the following error every time I try to parse JSON in my program. I can't seem to figure it out. "Expected to decode String but found an array instead.", underlyingError: nil Here is the code I have been struggling with: struct Book: Decodable { let id: Int let title: String let chapters: Int var pages: [Page]? } struct Page: Decodable { let id: Int let text: [String] } struct Chapter: Decodable { var chapterNumber: Int } func fetchJSON() { let urlString = "https://api.myjson.com/bins/kzqh3" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { (data, _, err) in if let err = err { print("Failed to fetch data from", err) return } guard let data = data else { return } do { let decoder = JSONDecoder() let books = try decoder.decode([Book].self, from: data) books.forEach({print($0.title)}) } catch let jsonErr { print("Failed to parse json:", jsonErr) } }.resume() }
Are you sure that's the real error message? Actually the error is supposed to be "Expected to decode String but found a dictionary instead." The value for key text is not an array of strings, it's an array of dictionaries struct Page: Decodable { let id: Int let text: [[String:String]] } The struct Chapter is not needed. Alternatively write a custom initializer and decode the dictionaries containing the chapter number as key and the text as value into an array of Chapter struct Book: Decodable { let id: Int let title: String let chapters: Int let pages: [Page] } struct Page: Decodable { let id: Int var chapters = [Chapter]() private enum CodingKeys : String, CodingKey { case id, chapters = "text" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(Int.self, forKey: .id) var arrayContainer = try container.nestedUnkeyedContainer(forKey: .chapters) while !arrayContainer.isAtEnd { let chapterDict = try arrayContainer.decode([String:String].self) for (key, value) in chapterDict { chapters.append(Chapter(number: Int(key)!, text: value)) } } } } struct Chapter: Decodable { let number : Int let text : String }
This is working: import UIKit class ViewController: UIViewController { private var books = [Book]() struct Book: Decodable { let id: Int let title: String let chapters: Int var pages: [Page] } struct Page: Decodable { let id: Int let text: [[String:String]] } override func viewDidLoad() { super.viewDidLoad() fetchJSON() } func fetchJSON() { let urlString = "https://api.myjson.com/bins/kzqh3" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { data, response, error in if error != nil { print(error!.localizedDescription) return } guard let data = data else { return } do { let decoder = JSONDecoder() self.books = try decoder.decode([Book].self, from: data) DispatchQueue.main.async { for info in self.books { print(info.title) print(info.chapters) print(info.pages[0].id) print(info.pages[0].text) print("-------------------") } } } catch let jsonErr { print("something wrong after downloaded: \(jsonErr) ") } }.resume() } } // print //Genesis //50 //1 //[["1": "In the beg...]] //------------------- //Exodus //40 //2 //[["1": "In the beginning God created...]] // If you need to print the value of each chapter in the book, I can use something like this: import UIKit class ViewController: UIViewController { private var books = [Book]() struct Book: Decodable { let id: Int let title: String let chapters: Int var pages: [Page] } struct Page: Decodable { let id: Int let text: [[String:String]] } override func viewDidLoad() { super.viewDidLoad() fetchJSON() } func fetchJSON() { let urlString = "https://api.myjson.com/bins/kzqh3" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { data, response, error in if error != nil { print(error!.localizedDescription) return } guard let data = data else { return } do { let decoder = JSONDecoder() self.books = try decoder.decode([Book].self, from: data) DispatchQueue.main.async { for info in self.books { print(info.title) print(info.chapters) print(info.pages[0].id) //print(info.pages[0].text) for cc in info.pages[0].text { for (key, value) in cc { print("\(key) : \(value)") } } print("-------------------") } } } catch let jsonErr { print("something wrong after downloaded: \(jsonErr) ") } }.resume() } } //Genesis //50 //1 //1 : In the beginning God ... //2 : But the earth became waste... //. //. //. //31 : And God saw everything... //------------------- //Exodus //40 //2 //1 : In the beginning God... //2 : But the earth became... //. //. //. //31 : And God saw everything