-1

I am trying to get response from Google's Book API. In there I can get response but for example, in some books have description or many other keys in response JSON. If I desing my structs according to with descriptions key, other books which not have description gave me dataCorrupted error and not decoding JSON. If I do otherwise, I get the same error on other books which have description. I hope I can explain myself. How can I solve it correctly?

Here my root class codable:

import Foundation

struct RootClass : Codable {

        let items : [Item]?
        let kind : String?
        let totalItems : Int?

        enum CodingKeys: String, CodingKey {
                case items = "items"
                case kind = "kind"
                case totalItems = "totalItems"
        }
    
        init(from decoder: Decoder) throws {
                let values = try decoder.container(keyedBy: CodingKeys.self)
                items = try values.decodeIfPresent([Item].self, forKey: .items)
                kind = try values.decodeIfPresent(String.self, forKey: .kind)
                totalItems = try values.decodeIfPresent(Int.self, forKey: .totalItems)
        }

}

I need to reach root -> items -> volumeInfo.

And here Item codable struct:

import Foundation

struct Item : Codable {

        let accessInfo : AccessInfo?
        let etag : String?
        let id : String?
        let kind : String?
        let saleInfo : SaleInfo?
        let searchInfo : SearchInfo?
        let selfLink : String?
        let volumeInfo : VolumeInfo?

        enum CodingKeys: String, CodingKey {
                case accessInfo = "accessInfo"
                case etag = "etag"
                case id = "id"
                case kind = "kind"
                case saleInfo = "saleInfo"
                case searchInfo = "searchInfo"
                case selfLink = "selfLink"
                case volumeInfo = "volumeInfo"
        }
    
        init(from decoder: Decoder) throws {
                let values = try decoder.container(keyedBy: CodingKeys.self)
            accessInfo = try AccessInfo(from: decoder)
                etag = try values.decodeIfPresent(String.self, forKey: .etag)
                id = try values.decodeIfPresent(String.self, forKey: .id)
                kind = try values.decodeIfPresent(String.self, forKey: .kind)
            saleInfo = try SaleInfo(from: decoder)
            searchInfo = try SearchInfo(from: decoder)
                selfLink = try values.decodeIfPresent(String.self, forKey: .selfLink)
            volumeInfo = try VolumeInfo(from: decoder)
        }

}

And Here I parse json :

func parseJSON(searchData: Data) -> [SearchedModel]?{
    
    let decode = JSONDecoder()
    do{
        let decodedData = try decode.decode(RootClass.self, from: searchData)
        // IN HERE I CAN USE FOR LOOP TO ITEMS AND GET VOLUME INFO DATAS BUT ITS ALL NIL

        return mainDataArr
    }catch{
        print(error)
        return nil
    }
    
}

When I try to loop over to items and get volume info datas its all nil. I can't understand why is this all nil? How can I solve it?

Here part of JSON 1 :

"kind": "books#volumes",
    "totalItems": 1196,
    "items": [
        {
            "kind": "books#volume",
            "id": "4qnmsgEACAAJ",
            "etag": "dYXW8bT6JB0",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/4qnmsgEACAAJ",
            "volumeInfo": {
                "title": "Sineklerin Tanrisi",
                "authors": [
                    "William Golding"
                ],
                "publishedDate": "2014-01-01",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_10",
                        "identifier": "9754582904"
                    },
                    {
                        "type": "ISBN_13",
                        "identifier": "9789754582901"
                    }
                ],
                "readingModes": {
                    "text": false,
                    "image": false
                },
                "pageCount": 261,
                "printType": "BOOK",
                "categories": [
                    "Boys"
                ],
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "preview-1.0.0",
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"
                },
                "language": "tr",
                "previewLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&cd=1&source=gbs_api",
                "infoLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&source=gbs_api",
                "canonicalVolumeLink": "https://books.google.com/books/about/Sineklerin_Tanrisi.html?hl=&id=4qnmsgEACAAJ"
            },
            "saleInfo": {
                "country": "TR",
                "saleability": "NOT_FOR_SALE",
                "isEbook": false
            },
            "accessInfo": {
                "country": "TR",
                "viewability": "NO_PAGES",
                "embeddable": false,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": false
                },
                "pdf": {
                    "isAvailable": false
                },
                "webReaderLink": "http://play.google.com/books/reader?id=4qnmsgEACAAJ&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "NONE",
                "quoteSharingAllowed": false
            }
        }

And here JSON 2 (with same request's response):

"kind": "books#volumes",
    "totalItems": 432,
    "items": [
        {
            "kind": "books#volume",
            "id": "yodWha1LmPsC",
            "etag": "2bZz2CDqiq4",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/yodWha1LmPsC",
            "volumeInfo": {
                "title": "Momo the Monkey Arrives",
                "authors": [
                    "Shariffa Keshavjee"
                ],
                "publisher": "Master Publishing",
                "publishedDate": "2012-09-21",
                "description": "Momo the Monkey Arrives is the first in a series of illustrated children's books about the rescue of a monkey and how his presence livens up the household of two children: a boy and a girl. Along the way, as they take care of Momo, Geno and Alid learn how to give the best possible care to a monkey like him, and how to be more responsible children. The adventures of Momo are based on a true story.",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_13",
                        "identifier": "9789966158987"
                    },
                    {
                        "type": "ISBN_10",
                        "identifier": "9966158987"
                    }
                ],
                "readingModes": {
                    "text": true,
                    "image": true
                },
                "pageCount": 28,
                "printType": "BOOK",
                "categories": [
                    "Juvenile Fiction"
                ],
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "1.4.4.0.preview.3",
                "panelizationSummary": {
                    "containsEpubBubbles": false,
                    "containsImageBubbles": false
                },
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
                },
                "language": "en",
                "previewLink": "http://books.google.com.tr/books?id=yodWha1LmPsC&pg=PT25&dq=momo&hl=&cd=1&source=gbs_api",
                "infoLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&source=gbs_api",
                "canonicalVolumeLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC"
            },
            "saleInfo": {
                "country": "TR",
                "saleability": "FOR_SALE",
                "isEbook": true,
                "listPrice": {
                    "amount": 35.04,
                    "currencyCode": "TRY"
                },
                "retailPrice": {
                    "amount": 35.04,
                    "currencyCode": "TRY"
                },
                "buyLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&rdid=book-yodWha1LmPsC&rdot=1&source=gbs_api",
                "offers": [
                    {
                        "finskyOfferType": 1,
                        "listPrice": {
                            "amountInMicros": 35040000,
                            "currencyCode": "TRY"
                        },
                        "retailPrice": {
                            "amountInMicros": 35040000,
                            "currencyCode": "TRY"
                        }
                    }
                ]
            },
            "accessInfo": {
                "country": "TR",
                "viewability": "PARTIAL",
                "embeddable": true,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": true
                },
                "pdf": {
                    "isAvailable": true
                },
                "webReaderLink": "http://play.google.com/books/reader?id=yodWha1LmPsC&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "SAMPLE",
                "quoteSharingAllowed": false
            },
            "searchInfo": {
                "textSnippet": "<b>Momo</b> the Monkey Adventure Series <b>Momo</b> the Monkey Arrives <b>Momo</b> Makes a <br>\nMess <b>Momo</b> Comes to the Rescue <b>Momo</b> Moves to the Orphanage Look out for <br>\nthese stories about <b>Momo</b> and his friends. More coming soon! Master Publishing<br>\n&nbsp;..."
            }
        }
mehmett
  • 111
  • 1
  • 12
  • Have properties optional (that can be nil/null) if needed, and maybe if the key isn't present in the JSON, use a custom `init(from decoder:)` and use `decodeIfPresent()` – Larme Jan 29 '21 at 13:38
  • Does this answer your question? [What is difference between optional and decodeIfPresent when using Decodable for JSON Parsing?](https://stackoverflow.com/questions/46292325/what-is-difference-between-optional-and-decodeifpresent-when-using-decodable-for) – Larme Jan 29 '21 at 13:38
  • In decodeIfPresent, I get JsonDecoder has no member decodeIfPresent error. – mehmett Jan 29 '21 at 14:01
  • Also my all properties are optional. – mehmett Jan 29 '21 at 14:05
  • https://developer.apple.com/documentation/swift/unkeyeddecodingcontainer/2966168-decodeifpresent should be there. I've used it (I'm not the only one). But code and also repdocible JSON which would have the two possible version (one with and one without the key/value) would help. – Larme Jan 29 '21 at 14:06
  • I need more explanation for that. Can you make it please? How can I use that with JsonDecoder? – mehmett Jan 29 '21 at 14:33
  • You should add 1) the exact error message you get 2) the definition of SearchedModel 3) example json that generates the error – Joakim Danielson Jan 29 '21 at 15:26

1 Answers1

0

The "data corrupted" error seems to be due to the presence of the \n in the textSnippet. If we take care of that manually, I can't reproduce any issue. Here is a complete (unlike your code) example that compiles and runs correctly in an iOS project, using the JSON you provided (patched up to be valid JSON):

let json1 = """
{
    "kind": "books#volumes",
    "totalItems": 1196,
    "items": [
        {
            "kind": "books#volume",
            "id": "4qnmsgEACAAJ",
            "etag": "dYXW8bT6JB0",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/4qnmsgEACAAJ",
            "volumeInfo": {
                "title": "Sineklerin Tanrisi",
                "authors": [
                    "William Golding"
                ],
                "publishedDate": "2014-01-01",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_10",
                        "identifier": "9754582904"
                    },
                    {
                        "type": "ISBN_13",
                        "identifier": "9789754582901"
                    }
                ],
                "readingModes": {
                    "text": false,
                    "image": false
                },
                "pageCount": 261,
                "printType": "BOOK",
                "categories": [
                    "Boys"
                ],
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "preview-1.0.0",
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"
                },
                "language": "tr",
                "previewLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&cd=1&source=gbs_api",
                "infoLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&source=gbs_api",
                "canonicalVolumeLink": "https://books.google.com/books/about/Sineklerin_Tanrisi.html?hl=&id=4qnmsgEACAAJ"
            },
            "saleInfo": {
                "country": "TR",
                "saleability": "NOT_FOR_SALE",
                "isEbook": false
            },
            "accessInfo": {
                "country": "TR",
                "viewability": "NO_PAGES",
                "embeddable": false,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": false
                },
                "pdf": {
                    "isAvailable": false
                },
                "webReaderLink": "http://play.google.com/books/reader?id=4qnmsgEACAAJ&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "NONE",
                "quoteSharingAllowed": false
            }
        }
    ]
}
"""

let json2 = """
{
    "kind": "books#volumes",
    "totalItems": 432,
    "items": [
        {
            "kind": "books#volume",
            "id": "yodWha1LmPsC",
            "etag": "2bZz2CDqiq4",
            "selfLink": "https://www.googleapis.com/books/v1/volumes/yodWha1LmPsC",
            "volumeInfo": {
                "title": "Momo the Monkey Arrives",
                "authors": [
                    "Shariffa Keshavjee"
                ],
                "publisher": "Master Publishing",
                "publishedDate": "2012-09-21",
                "description": "Momo the Monkey Arrives is the first in a series of illustrated children's books about the rescue of a monkey and how his presence livens up the household of two children: a boy and a girl. Along the way, as they take care of Momo, Geno and Alid learn how to give the best possible care to a monkey like him, and how to be more responsible children. The adventures of Momo are based on a true story.",
                "industryIdentifiers": [
                    {
                        "type": "ISBN_13",
                        "identifier": "9789966158987"
                    },
                    {
                        "type": "ISBN_10",
                        "identifier": "9966158987"
                    }
                ],
                "readingModes": {
                    "text": true,
                    "image": true
                },
                "pageCount": 28,
                "printType": "BOOK",
                "categories": [
                    "Juvenile Fiction"
                ],
                "maturityRating": "NOT_MATURE",
                "allowAnonLogging": false,
                "contentVersion": "1.4.4.0.preview.3",
                "panelizationSummary": {
                    "containsEpubBubbles": false,
                    "containsImageBubbles": false
                },
                "imageLinks": {
                    "smallThumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
                    "thumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
                },
                "language": "en",
                "previewLink": "http://books.google.com.tr/books?id=yodWha1LmPsC&pg=PT25&dq=momo&hl=&cd=1&source=gbs_api",
                "infoLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&source=gbs_api",
                "canonicalVolumeLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC"
            },
            "saleInfo": {
                "country": "TR",
                "saleability": "FOR_SALE",
                "isEbook": true,
                "listPrice": {
                    "amount": 35.04,
                    "currencyCode": "TRY"
                },
                "retailPrice": {
                    "amount": 35.04,
                    "currencyCode": "TRY"
                },
                "buyLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&rdid=book-yodWha1LmPsC&rdot=1&source=gbs_api",
                "offers": [
                    {
                        "finskyOfferType": 1,
                        "listPrice": {
                            "amountInMicros": 35040000,
                            "currencyCode": "TRY"
                        },
                        "retailPrice": {
                            "amountInMicros": 35040000,
                            "currencyCode": "TRY"
                        }
                    }
                ]
            },
            "accessInfo": {
                "country": "TR",
                "viewability": "PARTIAL",
                "embeddable": true,
                "publicDomain": false,
                "textToSpeechPermission": "ALLOWED",
                "epub": {
                    "isAvailable": true
                },
                "pdf": {
                    "isAvailable": true
                },
                "webReaderLink": "http://play.google.com/books/reader?id=yodWha1LmPsC&hl=&printsec=frontcover&source=gbs_api",
                "accessViewStatus": "SAMPLE",
                "quoteSharingAllowed": false
            },
            "searchInfo": {
                "textSnippet": "<b>Momo</b> the Monkey Adventure Series <b>Momo</b> the Monkey Arrives <b>Momo</b> Makes a <br>\\nMess <b>Momo</b> Comes to the Rescue <b>Momo</b> Moves to the Orphanage Look out for <br>\\nthese stories about <b>Momo</b> and his friends. More coming soon! Master Publishing<br>\\n&nbsp;..."
            }
        }
    ]
}
"""

struct Base : Codable {
    let kind : String
    let totalItems : Int
    let items : [Items]
}
struct Items : Codable {
    let kind : String
    let id : String
    let etag : String
    let selfLink : String
    let volumeInfo : VolumeInfo
    let saleInfo : SaleInfo?
    let accessInfo : AccessInfo
    let searchInfo : SearchInfo?
}
struct SaleInfo : Codable {
    let country : String
    let saleability : String
    let isEbook : Bool
    let listPrice : ListPrice?
    let retailPrice : RetailPrice?
    let buyLink : String?
    let offers : [Offers]?
}
struct Offers : Codable {
    let finskyOfferType : Int
    let listPrice : ListPrice
    let retailPrice : RetailPrice
}
struct ListPrice : Codable {
    let amountInMicros : Int?
    let currencyCode : String
}
struct ReadingModes : Codable {
    let text : Bool
    let image : Bool
}
struct Epub : Codable {
    let isAvailable : Bool
}
struct Pdf : Codable {
    let isAvailable : Bool
}
struct RetailPrice : Codable {
    let amountInMicros : Int?
    let currencyCode : String
}
struct SearchInfo : Codable {
    let textSnippet : String
}
struct ImageLinks : Codable {
    let smallThumbnail : String
    let thumbnail : String
}
struct IndustryIdentifiers : Codable {
    let type : String
    let identifier : String
}
struct PanelizationSummary : Codable {
    let containsEpubBubbles : Bool
    let containsImageBubbles : Bool
}
struct VolumeInfo : Codable {
    let title : String
    let authors : [String]
    let publisher : String?
    let publishedDate : String
    let description : String?
    let industryIdentifiers : [IndustryIdentifiers]
    let readingModes : ReadingModes
    let pageCount : Int
    let printType : String
    let categories : [String]
    let maturityRating : String
    let allowAnonLogging : Bool
    let contentVersion : String
    let panelizationSummary : PanelizationSummary?
    let imageLinks : ImageLinks
    let language : String
    let previewLink : String
    let infoLink : String
    let canonicalVolumeLink : String
}
struct AccessInfo : Codable {
    let country : String
    let viewability : String
    let embeddable : Bool
    let publicDomain : Bool
    let textToSpeechPermission : String
    let epub : Epub
    let pdf : Pdf
    let webReaderLink : String
    let accessViewStatus : String
    let quoteSharingAllowed : Bool
}


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let data1 = json1.data(using: .utf8)!
        do {
            let result = try JSONDecoder().decode(Base.self, from: data1)
            print("success1")
            print(result)
        } catch {
            print(error)
        }
        let data2 = json2.data(using: .utf8)!
        do {
            let result = try JSONDecoder().decode(Base.self, from: data2)
            print("success2")
            print(result)
        } catch {
            print(error)
        }


    }


}
matt
  • 515,959
  • 87
  • 875
  • 1,141