Swift Codable Json Response - ios

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)

Related

How to parse Wikipedia JSON Dictionary with Swift?

I'm new to the Wikipedia API and I have been trying to parse the image url from the API. The JSON I'm trying to parse is as follows:
API:
https://en.wikipedia.org/w/api.php?action=query&titles=tokyo&prop=pageimages&format=json
JSON Result:
{"batchcomplete": "",
"query": {
"normalized": [
{
"from": "tokyo",
"to": "Tokyo"
}
],
"pages": {
"30057": {
"pageid": 30057,
"ns": 0,
"title": "Tokyo",
"thumbnail": {
"source": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg",
"width": 50,
"height": 27
},
"pageimage": "Skyscrapers_of_Shinjuku_2009_January.jpg"
}
}
}
}
Below are the struct I created to parse the data. I can see the url when I print it to the console, but since "source" is nested under "thumbnail", which lives in the value of the [String:Page] dict pair, I can't figure out a way to access it. How do I parse data in a dictionary like this? Thank you for your help in advance.
struct WikiAPIResults: Codable {
let batchcomplete: String?
let query: Query?
}
struct Query: Codable {
let normalized: [Normalized]?
let pages: [String:Pages]? // <- I can get to here
}
struct Normalized: Codable {
let from, to: String?
}
struct Pages: Codable {
let pageid, ns: Int?
let title: String?
let thumbnail: Thumbnail?
let pageimage: String?
}
struct Thumbnail: Codable {
let source: String? // <- But I want to grab this
let width, height: Int?
}
func fetchImageFromWikipedia(imageKeyword: String, completion: #escaping (WikiAPIResults) -> Void) {
var urlComponents = URLComponents(string: "https://en.wikipedia.org/w/api.php?")!
urlComponents.queryItems = [
"action": "query",
"titles": imageKeyword,
"prop": "pageimages",
"format": "json"].map { URLQueryItem(name: $0.key, value: $0.value) }
let task = URLSession.shared.dataTask(with: urlComponents.url!) { data, response, error in
let jsonDecoder = JSONDecoder()
if let data = data,
let result = try? jsonDecoder.decode(WikiAPIResults.self, from: data) {
completion(result)
}
}
task.resume()
}
fetchImageFromWikipedia(imageKeyword: "Tokyo") { result in
print(result.query?.pages?.values)
}
Do you mean gathering all thumbnail sources?
fetchImageFromWikipedia(imageKeyword: "Tokyo") { result in
let pages = result.query?.pages?.compactMap { $0.value } ?? []
let thumbnailSources = pages.compactMap { $0.thumbnail?.source }
print(thumbnailSources)
}
This works with your example perfectly:
import Foundation
struct Response: Decodable {
struct Query: Decodable {
struct NormalizedQuery: Decodable {
let from: String
let to: String
}
struct Page: Decodable {
struct Thumbnail: Decodable {
let source: URL
let width: Int
let height: Int
}
let id: Int
let ns: Int
let title: String
let thumbnail: Thumbnail
let pageImage: String
private enum CodingKeys: String, CodingKey {
case id = "pageid"
case ns
case title
case thumbnail
case pageImage = "pageimage"
}
}
let normalized: [NormalizedQuery]
let pages: [String : Page]
}
let batchComplete: String
let query: Query
private enum CodingKeys: String, CodingKey {
case batchComplete = "batchcomplete"
case query
}
}
let responseString = """
{
"batchcomplete" : "",
"query" : {
"normalized" : [
{
"from" : "tokyo",
"to" : "Tokyo"
}
],
"pages" : {
"30057" : {
"pageid" : 30057,
"ns" : 0,
"title" : "Tokyo",
"thumbnail" : {
"source" : "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg",
"width" : 50,
"height" : 27
},
"pageimage" : "Skyscrapers_of_Shinjuku_2009_January.jpg"
}
}
}
}
"""
let responseData = responseString.data(using: .utf8)!
let response = try! JSONDecoder().decode(Response.self, from: responseData)
print(response)
// Response(batchComplete: "", query: __lldb_expr_18.Response.Query(normalized: [__lldb_expr_18.Response.Query.NormalizedQuery(from: "tokyo", to: "Tokyo")], pages: ["30057": __lldb_expr_18.Response.Query.Page(id: 30057, ns: 0, title: "Tokyo", thumbnail: __lldb_expr_18.Response.Query.Page.Thumbnail(source: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Skyscrapers_of_Shinjuku_2009_January.jpg/50px-Skyscrapers_of_Shinjuku_2009_January.jpg, width: 50, height: 27), pageImage: "Skyscrapers_of_Shinjuku_2009_January.jpg")]))

How to retrieve data from json response

I am trying to get data from json response, and the response format is mentioning below. I want to fetch "recipient" dictionary, and need to show in table.each cell contains name and unique id and image. How to get this dictionary to story in local dictionary?
{
"success": 1,
"status": 200,
"data": {
"chat": [
{
"id": 5,
"status": 0,
"created_at": "2019-02-19 13:29:15",
"updated_at": "2019-02-19 13:29:15",
"recipient": {
"id": 5,
"unique_id": "10004",
"name": "Pandu",
"avatar": "https://www.planetzoom.co.in/img/default_avatar_female.png"
},
"conversation": {
"id": 67,
"chat_id": 5,
"user_id": 4,
"type": 0,
"message": "I have sent a msg now",
"status": 0,
"created_at": "2019-02-26 04:02:20"
}
},
{
"id": 3,
"status": 0,
"created_at": "2019-02-19 13:17:49",
"updated_at": "2019-02-19 13:17:49",
"recipient": {
"id": 8,
"unique_id": "10007",
"name": "Mahitha",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/cZt9yQlBzIEewOdQ1lYZhl3dFiOv2k3bxG7HLOzR.jpeg"
},
"conversation": {
"id": 57,
"chat_id": 3,
"user_id": 4,
"type": 0,
"message": "Hi",
"status": 0,
"created_at": "2019-02-24 13:04:29"
}
},
{
"id": 2,
"status": 0,
"created_at": "2019-02-19 07:59:05",
"updated_at": "2019-02-19 07:59:05",
"recipient": {
"id": 1,
"unique_id": "1111",
"name": "Angadi World Tech",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/NlVzdUAfmLfIG9677szYZz7NkWyY4ULHAqnlCiiV.png"
},
"conversation": {
"id": 21,
"chat_id": 2,
"user_id": 4,
"type": 0,
"message": "Hi\\uD83D\\uDE0A",
"status": 0,
"created_at": "2019-02-21 10:35:26"
}
}
]
}
}
The best way to decode json in my opinion is to use Codable
I've created a few structs to represent the data and to decode it, please note this json wasn't valid so have had to wrap it in {}
Here's the json:
let jsonString = """
{
"chat": [
{
"id": 12,
"status": 0,
"created_at": "2019-02-22 04:57:12",
"updated_at": "2019-02-22 04:57:12",
"recipient": {
"id": 26,
"unique_id": "10024",
"name": "Kaverinew",
"avatar": "https://www.planetzoom.co.in/storage/user/avatar/1PyI4ceM3zPsG1fxbfatktWUT75sOE2Ttah8ctIp.png"
},
"conversation": {
"id": 65,
"chat_id": 12,
"user_id": 4,
"type": 1,
"message": "https://www.planetzoom.co.in/storage/chat/message/e759KWdSBegwXslAoS2xst0lohbbjNZMdpVnbxQG.png",
"status": 0,
"created_at": "2019-02-25 15:39:24"
}
},
{
"id": 6,
"status": 0,
"created_at": "2019-02-20 07:16:35",
"updated_at": "2019-02-20 07:16:35",
"recipient": {
"id": 7,
"unique_id": "10006",
"name": "Hema",
"avatar": "https://www.planetzoom.co.in/img/default_avatar_female.png"
},
"conversation": {
"id": 44,
"chat_id": 6,
"user_id": 4,
"type": 1,
"message": "https://www.planetzoom.co.in/storage/chat/message/qJjOtCRcBKBuq3UKaKVuVOEIQhaVPeJr3Bd4NoLo.png",
"status": 0,
"created_at": "2019-02-22 10:17:49"
}
}
]
}
Here are the structs:
struct Recipient: Codable {
var identifier: Int
var unique_id: Int
var name: String
var avatar: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case unique_id = "unique_id"
case name = "name"
case avatar = "avatar"
}
}
struct Conversation: Codable {
var identifier: Int
var chat_id: Int
var user_id: Int
var conversationType: Int
var message: String
var status: Int
var created_at: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case chat_id = "chat_id"
case user_id = "user_id"
case conversationType = "type"
case message = "message"
case status = "status"
case created_at = "created_at"
}
}
struct Chat: Codable {
var identifier: Int
var status: Int
var created_at: String
var updated_at: String
enum CodingKeys: String, CodingKey {
case identifier = "id"
case status = "status"
case created_at = "created_at"
case updated_at = "updated_at"
}
}
struct RootObject: Codable {
var chats: [Chat]
enum CodingKeys: String, CodingKey {
case chats = "chat"
}
}
And here is how you decode it:
if let jsonData = jsonString.data(using: .utf8) {
do {
let root = try JSONDecoder().decode(RootObject.self, from: jsonData)
} catch {
print(error)
}
}
Assuming you already have a Data object representing your JSON you can use JSONSerialization to convert it to concrete Swift object. Once that is done you simply need to go step by step and extract the data. Something like the following should work nicely:
func retrieveRecipients(jsonData: Data?) throws -> [[String: Any]] {
guard let data = jsonData else { throw NSError(domain: "Parsing Recipients", code: 404, userInfo: ["dev_message": "Null JSON data inserted"]) }
guard let parsedJSON = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) else { throw NSError(domain: "Parsing Recipients", code: 500, userInfo: ["dev_message": "Data could not be parsed as JSON"]) }
guard let object = parsedJSON as? [String: Any] else { throw NSError(domain: "Parsing Recipients", code: 500, userInfo: ["dev_message": "Parsed JSON is not a dictionary"]) }
guard let items = object["chat"] as? [[String: Any]] else { throw NSError(domain: "Parsing Recipients", code: 404, userInfo: ["dev_message": "JSON is missing \"chat\" array"]) }
return items.compactMap { $0["recipient"] as? [String: Any] }
}
This is all the safety enabled. Otherwise you could do it very shortly:
func retreiveRecipientsStrict(jsonData: Data?) -> [[String: Any]] {
return ((try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any])["chat"] as! [[String: Any]]).compactMap { $0["recipient"] as? [String: Any] }
}
But this will crash if there is a mistake and it will be extremely hard to debug what went wrong.

Parsing the JSON iOS-Swift

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"
}]
}
}

Having trouble decoding JSON in Swift 4

Here is the response JSON:
{
"feed": {
"title": "Top Albums",
"id": "https://rss.itunes.apple.com/api/v1/us/apple-music/top-albums/all/25/explicit.json",
"author": {
"name": "iTunes Store",
"uri": "http://wwww.apple.com/us/itunes/"
},
"links": [
{
"self": "https://rss.itunes.apple.com/api/v1/us/apple-music/top-albums/all/25/explicit.json"
},
{
"alternate": "https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewTop?genreId=34&popId=82&app=music"
}
],
"copyright": "Copyright © 2018 Apple Inc. All rights reserved.",
"country": "us",
"icon": "http://itunes.apple.com/favicon.ico",
"updated": "2018-07-17T01:41:38.000-07:00",
"results": [
{
"artistName": "Drake",
"id": "1405365674",
"releaseDate": "2018-06-29",
"name": "Scorpion",
"kind": "album",
"copyright": "℗ 2018 Young Money/Cash Money Records",
"artistId": "271256",
"artistUrl": "https://itunes.apple.com/us/artist/drake/271256?app=music",
"artworkUrl100": "https://is4-ssl.mzstatic.com/image/thumb/Music125/v4/5d/9b/97/5d9b97d6-9f78-e43b-7ba7-c2c42f53a166/00602567879121.rgb.jpg/200x200bb.png",
"genres": [
{
"genreId": "18",
"name": "Hip-Hop/Rap",
"url": "https://itunes.apple.com/us/genre/id18"
},
{
"genreId": "34",
"name": "Music",
"url": "https://itunes.apple.com/us/genre/id34"
}
],
"url": "https://itunes.apple.com/us/album/scorpion/1405365674?app=music"
},
...
And this is my code attempting to decode the above JSON:
struct object: Decodable {
struct feed: Decodable {
let title: String?
let id: Int?
struct Author: Decodable {
let name: String?
let uri: String?
}
let author: Author?
struct Link: Decodable {
let url: String?
private enum CodingKeys: String, CodingKey {
case url = "self"
}
}
let links: [Link]?
let copyright: String?
let country: String?
let icon: String?
let updated: String?
let results: [Album]?
}
}
struct Album: Decodable {
let artistName: String?
let id: Int?
let releaseDate: String?
let name: String?
let artworkUrl100: String?
let kind: String?
let copyright: String?
let artistId: Int?
let artistUrl: String?
struct Genre: Decodable {
let genreId: Int?
let name: String?
let url: String?
}
let genres: [Genre]?
let url: String?
}
I am attempting to obtain the results with album name, artist name and image url. I am having difficulty understanding how to construct a suitable structure to obtain the data with a nested json.
When I attempt to obtain the data within my completion block, i just end up getting nil values for everything.
//Networking
let jsonString = "https://rss.itunes.apple.com/api/v1/us/apple-music/top-albums/all/25/explicit.json"
guard let url = URL(string: jsonString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
do {
let obj = try JSONDecoder().decode(object.feed.self, from: data)
print(obj)
} catch let jsonError {
print("Error with json", jsonError)
}
}.resume()
And my result is all nil:
feed(title: nil, id: nil, author: nil, links: nil, copyright: nil, country: nil, icon: nil, updated: nil, results: nil)
You have a few issues.
Firstly, the outermost structure is an object under the key feed
You need:
struct object: Decodable {
let feed: Feed
}
struct Feed: Decodable {
let title: String
let id: String
let author: Author
struct Link: Decodable {
let url: String?
private enum CodingKeys: String, CodingKey {
case url = "self"
}
}
let links: [Link]
let copyright: String
let country: String
let icon: String
let updated: String
let results: [Album]
}
and then you would decode it via:
do {
let obj = try JSONDecoder().decode(object.self, from: data)
print(obj)
} catch let jsonError {
print("Error with json", jsonError)
}
Note that all of the "ids" are Strings not Ints

Modelling an 'object' type to decode JSON

I'm making multiple calls to the Apple Music API which is returning an array of Resource objects. The Resource object has a property called attributes of type object which varies depending on whether it is a Song, Playlist, or Album.
How do I model the resource object so I can decode the JSON and create Song, Playlist, and Album objects?
struct Resource {
let id : String?
let type : String?
let href : String?
let attributes : "What goes here?"
}
Update 1:
I tried Joe's second recommendation and set up my structs like so:
struct Resource: Decodable{
enum Attribute {
case song(Song), playlist(Playlist)
}
let id : String?
let type : String?
let href : String?
let attributes: Attribute?
enum CodingKeys : CodingKey{
case id, type, href, attributes
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decode(String.self, forKey: .id)
type = try values.decode(String.self, forKey: .type)
href = try values.decode(String.self, forKey: .href)
switch type {
case "library-songs":
attributes = try .song(values.decode(Song.self, forKey: .attributes))
case "library-playlists":
attributes = try .playlist(values.decode(Playlist.self, forKey: .attributes))
default:
attributes = nil
}
}
}
struct Song : Decodable {
let playParams : PlayParams?
let trackNumber : Int?
let durationInMillis : Int?
let name : String?
let albumName : String?
let artwork : Artwork?
let contentRating : String?
let artistName : String?
}
struct Artwork : Decodable {
let width : Int?
let height : Int?
let url : String?
}
struct PlayParams : Decodable {
let id : String?
let kind : String?
let isLibrary : Bool?
}
The sample JSON looks like this for song:
{
"data": [
{
"id": "i.4YBNbl3IXVJQRM",
"type": "library-songs",
"href": "/v1/me/library/songs/i.4YBNbl3IXVJQRM",
"attributes": {
"albumName": "\"Awaken, My Love!\"",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is5-ssl.mzstatic.com/image/thumb/Music71/v4/00/d0/d7/00d0d743-b0de-31d8-09eb-0796269bb555/UMG_cvrart_00044003187658_01_RGB72_1800x1800_16UMGIM77118.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 326933,
"playParams": {
"id": "i.4YBNbl3IXVJQRM",
"kind": "song",
"isLibrary": true
},
"artistName": "Childish Gambino",
"trackNumber": 6,
"name": "Redbone",
"contentRating": "explicit"
}
},
{
"id": "i.mmpeOrZiLqoKOv",
"type": "library-songs",
"href": "/v1/me/library/songs/i.mmpeOrZiLqoKOv",
"attributes": {
"albumName": "Funk Wav Bounces Vol. 1",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is5-ssl.mzstatic.com/image/thumb/Music127/v4/8b/37/23/8b372308-f764-d03a-5bda-a7a456292547/886446469607.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 272659,
"playParams": {
"id": "i.mmpeOrZiLqoKOv",
"kind": "song",
"isLibrary": true
},
"artistName": "Calvin Harris",
"trackNumber": 4,
"name": "Rollin (feat. Future & Khalid)",
"contentRating": "explicit"
}
},
{
"id": "i.JL1aVxNtzmYDJG",
"type": "library-songs",
"href": "/v1/me/library/songs/i.JL1aVxNtzmYDJG",
"attributes": {
"albumName": "The Weekend (Funk Wav Remix) - Single",
"artwork": {
"width": 1200,
"height": 1200,
"url": "https://is4-ssl.mzstatic.com/image/thumb/Music118/v4/aa/d5/e5/aad5e5e3-dff5-7d8f-5747-b695ad9f2299/886446852157.jpg/{w}x{h}bb.jpg"
},
"durationInMillis": 171806,
"playParams": {
"id": "i.JL1aVxNtzmYDJG",
"kind": "song",
"isLibrary": true
},
"artistName": "SZA & Calvin Harris",
"trackNumber": 1,
"name": "The Weekend (Funk Wav Remix)"
}
}
]
}
When I decode the data using:
let resource = try? JSONDecoder().decode([Resource].self, from: data!)
print(resource!)
I get a fatal error: Unexpectedly found nil while unwrapping an Optional value
Update 2:
I figured out the issue. The extra layer on top was screwing up the decoding. I added another level:
struct Welcome: Codable {
let data: [Datum]
}
struct Datum: Codable {
let id, type, href: String
let attributes: Attributes
}
struct Attributes: Codable {
let albumName: String
let artwork: Artwork
let durationInMillis: Int
let playParams: PlayParams
let artistName: String
let trackNumber: Int
let name: String
let contentRating: String?
}
struct Artwork: Codable {
let width, height: Int
let url: String
}
struct PlayParams: Codable {
let id, kind: String
let isLibrary: Bool
}
This just works for songs but I will try reimplementing for both songs and playlists.

Resources