1

I want to parse the following JSON in order to get the ID of a random article from Wikipedia's API and use it in Swift:

{
"batchcomplete": "",
"continue": {
    "rncontinue": "0.067678657404|0.067678667039|13394072|0",
    "continue": "-||"
},
"query": {
    "random": [
        {
            "id": 34538560,
            "ns": 3,
            "title": "User talk:59.188.42.121"
        }
    ]
}
}

I want to be able to access the "id" and "title" values from it, and I currently have the following to access "query":

let url = URL(string: "https://en.wikipedia.org/w/api.php?action=query&list=random&rnlimit=1&format=json")
    URLSession.shared.dataTask(with: url!) { (data, response, err) in
        guard let data = data else { return }
        if err != nil {
            print(err!)
        } else {
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
                if let result = json! as? [String: AnyObject] {
                    if let result = result["query"]! as? [String: AnyObject] {
                        print(result)
                    }
                }
            } catch {
                print("Error")
            }
        }
    }.resume()

Right now, type-casting my way down is not something I'm proud of doing, and it gets very confusing very fast. I've also tried type-casting once by doing something like the following, to no avail:

[String: [String: [String:AnyObject]]]

Is there a better way to access these values? Any help would be greatly appreciated!

1 Answer 1

3

If you are using Swift 4, there's Codable. Using Codable involves defining custom structs / classes for the JSON but apps like quicktype.io can make that a piece of cake: you just paste the JSON and it generates the structs for you.

First, the struct to hold the response from Wikipedia:

struct Response: Codable {
    struct Query: Codable {
        let random: [Random]
    }

    struct Random: Codable {
        let id, ns: Int
        let title: String
    }

    struct Continue: Codable {
        let rncontinue, continueContinue: String

        enum CodingKeys: String, CodingKey {
            case rncontinue
            case continueContinue = "continue"
        }
    }

    let batchcomplete: String
    let `continue`: Continue
    let query: Query

    enum CodingKeys: String, CodingKey {
        case batchcomplete, `continue`, query
    }
}

And decoding the JSON:

let url = URL(string: "https://en.wikipedia.org/w/api.php?action=query&list=random&rnlimit=1&format=json")
URLSession.shared.dataTask(with: url!) { (data, response, err) in
    guard let data = data else { return }
    guard err == nil else { print(err!); return }

    do {
        let response = try JSONDecoder().decode(Response.self, from: data)
        if let firstArticle = response.query.random.first {
            print(firstArticle)
        } else {
            print("No Article")
        }
    } catch {
        print(error)
    }
}.resume()
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.