简体   繁体   中英

Google Books API parsing

So I'm trying to parse Google Books API respond. I want to get title, description, thumbnailUrl, authors and published data. Here is the problem :

func getBooksFrom(completion: @escaping (Result<[[String: AnyObject]]>) -> Void) {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard error == nil else { return completion(.Error(error!.localizedDescription)) }
        guard let data = data else { return
            completion(.Error(error!.localizedDescription)) }
        do {
            if let json = try JSONSerialization.jsonObject(with: data, options: [.mutableContainers]) as? [String: AnyObject] {
                if let items = json["items"] as? [[String: AnyObject]] {
                    DispatchQueue.main.async {
                        completion(.Succes(items))
                    }
                }
            }
        } catch let error {
            print(error.localizedDescription)
            return completion(.Error(error.localizedDescription))
        }
    }.resume()
}

And on my View Controller in the ViewDidLoad i have

let service = ApiService()
    service.getBooksFrom { (result) in
        switch result {
        case .Succes(let data):
            self.parseData(array: data)
        case .Error(let message):
            self.showAlertWith(title: "Error", and: message)
        }
    }

So that's pretty simple parsing, but... When I want to map items into Book Object i have to :

func parseData(_ data: [[String: AnyObject]]) -> [Book]{
    for item in data {
        if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
        let books = data.map { (jsonDictionary) -> Book in
            let title = volumeInfo["title"] as? String ?? ""
            let publishedData = volumeInfo["publishedDate"] as? String ?? ""
            let authors = volumeInfo["authors"] as? [String] ?? [""]

            let description = volumeInfo["description"] as? String ?? ""
            let newBook = Book(title: title, publishedData: publishedData, description: description)
            return newBook
        }
        return books
        }
    }
    return [Book]()
}

Which is super awful way to do it.. You have to return Book on the bottom, because of the for-loop, and VolumeInfo is next Dictionary, so I really don't know exactly how to map it and get for example authors, because it's next Array..

One sample JSON object:

   {  
   "items":[  
      {  
         "volumeInfo":{  
            "title":"The Ancestor's Tale",
            "subtitle":"A Pilgrimage to the Dawn of Life",
            "authors":[  
               "Richard Dawkins",
               "Yan Wong"
            ]
            "publishedDate":"2016-04-28",
            "description":"A fully updated ",
            "imageLinks":{  
               "smallThumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
               "thumbnail":"http://books.google.com/books/content?id=vzbVCQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
            }
}    
]}

So this is quite simple when you have array of String : Value, but how should you map in proper way, when you have for example dictionaries in dictionary VolumeInfo or array of strings like authors?

I personally find the way to parse objects in swift with URLSession relatively clumsy. Whenever I can I use Alamofire in combination with the AlamofireObjectMapper .

This allows you to create a simple object. For example:

class Book: Mappable {
      var title: String?
      var subtitle: String?
      var description: String?

      required init?(map: Map){

      }

      func mapping(map: Map) {
        title <- map["title"]
        subtitle <- map["subtitle"]
        description <- map["description"]
      }
}

When you make a request, you can then use the responseObject method to directly parse your object and assign the proper types.

Alamofire.request(URL).responseObject { (response: DataResponse<Book>) in
  let book = response.result.value
  print(book?.title)
}

For this example, I simply parsed only one book. But the concept can also be easily extended to arrays or nested json objects. I personally find this leads to much cleaner code than using URLSession directly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM