skip to Main Content

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)
}

2

Answers


  1. 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)
    }
    
    Login or Signup to reply.
  2. 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")]))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search