-1

I have json response that I need to parse that, according to the https://newsapi.org web site, should look like:

{
    "status": "ok",
    "totalResults": 4498,
    "articles": [{
        "source": {
            "id": null,
            "name": "Techweekeurope.co.uk"
        },
        "author": null,
        "title": "Top ten cloud service providers for reliability and price",
        "description": "In a time where the reliability and stability of cloud service providers comes into spotlight, we pick our top ten that will help you propel your business to the next level. We recently talked about building your own local network with a Raspberry Pi starter …",
        "url": "https://www.techweekeurope.co.uk/top-ten-cloud-service-providers-reliability-price/",
        "urlToImage": "https://www.techweekeurope.co.uk/wp-content/uploads/2020/01/Cloud-Service-Providers.gif",
        "publishedAt": "2020-01-04T16:17:00Z",
        "content": "In a time where the reliability and stability of cloud service providers comes into spotlight, we pick our top ten that will help you propel your business to the next level. We recently talked about building your own local network with a Raspberry Pi starter … [+4441 chars]"
    }, ...]
}

I created structures for parse it

import Foundation

struct Article: Codable {
    var source: Source
    var author: String?
    var title: String
    var description: String
    var url: URL
    var urlToImage: URL?
    var content: String

    enum codingKeys: String, CodingKey {
        case source
        case author
        case title
        case description
        case url
        case urlToImage
        case content
    }
}

struct Source: Codable {
    var name: String

}

struct Articles: Codable {
    var articles: [Article]
}

And I created class network service class

class NetworkService {

    // MARK: - Methods
    func parseJSON(from url: URL) {

        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                let decoder = JSONDecoder()

                let articleData = try decoder.decode(Articles.self, from: data!)
                print(articleData.articles.description)
            } catch {
                print(error)
            }
        }
        task.resume()
    }
}

In console I have this:

keyNotFound(CodingKeys(stringValue: "articles", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"articles\", intValue: nil) (\"articles\").", underlyingError: nil))

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Valter
  • 41
  • 10
  • @Sh_Khan, this is complete erroк – Valter Jan 04 '20 at 15:54
  • @Sh_Khan this is the my json. I talked it from newsapi.org – Valter Jan 04 '20 at 15:56
  • Maybe you should check the `error` and `response` parameters in case your request is not correct. My guess is you get some kind of error response back so that the json contains completely different data from what you are expecting. – Joakim Danielson Jan 04 '20 at 16:04
  • @Rob In articles there are a lot of elements. I show only one but others looks like the first – Valter Jan 04 '20 at 16:04
  • @Rob I use newsapi.org – Valter Jan 04 '20 at 16:08
  • I’ve removed those `-` characters to avoid confusion for future readers, as they were not really part of the JSON, but just user interface controls for expanding and collapsing sections of JSON on https://newsapi.org web site. – Rob Jan 04 '20 at 17:07

1 Answers1

2

Your error is telling you that the JSON was valid, but that it was unable to find any articles key in the response.

I’d suggest including status and message in your definition of Articles and make articles property an optional. The status might not be "ok". Regardless, articles is obviously absent.

struct Articles: Codable {
    let articles: [Article]?
    let status: String
    let message: String?
    let code: String?
}

For example, if you don’t supply a valid key, you’ll get a response like

{
    "status": "error",
    "code": "apiKeyInvalid",
    "message": "Your API key is invalid or incorrect. Check your key, or go to https://newsapi.org to create a free API key."
}

You may want to handle the case where articles may be absent if there is an error, by making it optional.


Unrelated, but the forced unwrapping operator for data is dangerous. If you have some network error, your app will crash. I’d suggest unwrapping it, e.g.:

func parseJSON(from url: URL) {

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        guard let data = data, error == nil else {
            print(error ?? "Unknown error")
            return
        }

        do {
            let articleData = try JSONDecoder().decode(Articles.self, from: data)
            guard let articles = articleData.articles else {
                print("No articles", articleData.status, articleData.message ?? "No message")
                return
            }

            for article in articles {
                print(article.description)
            }
        } catch {
            print(error)
        }
    }
    task.resume()
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044