Search code examples
jsonswiftalamofirewordpress-rest-api

Parsing nested JSON with Alamofire 4


So I have been trying all day to parse JSON from my WordPress REST API using Alomofire 4, I have tried everything I could find that is/was related to my issue yet I still can't manage to fix my issue.

The goal is just to do a request from the API and print it out, from there I can manage but since the JSON seems to be having nested arrays/dictionaries I have a hard time figuring out what to use.

My Code:

Alamofire.request(_newsURL).responseJSON { response in
        print(response.result)

        if let json = response.result.value as? [Any] {

            print("JSON: \(json)")
        }

        if let dict = response.result.value as? Dictionary<String, AnyObject>{

            print(response.result.value)

            if let slug = dict["slug"] as? String {

                self._newsSlug = slug
            }

            print("Hello News")
            print(self._newsURL)
            print(self._newsSlug)
        } else {
            print("Found Nothing")
        }
    }

The API: http://www.wsvh.nl/wp-json/wp/v2/posts

My goal is to simply call and print out stuff such as the title (which is btw also nested even more?). I was trying to get it work with just the slug since that I not as nested as the rendered title, so I figured I should begin with the most simple part but I can't even manage to get that to work.

Thanks in advance.


Solution

  • The API returns an array of dictionaries where each dictionary represents a Post of type [String: Any]:

    Alamofire.request(_newsURL).responseJSON { response in
      if let posts = response.result.value as? [[String: Any]] {
        posts.forEach { post in
          if let slug = post["slug"] as? String {
            print("Slug: \(slug)")
          }
          if let title = post["title"] as? [String: String] {
            print("Title: \(title["rendered"])")
          }
          if let categories = post["categories"] as? [Int] {
            print("Categories: \(categories)")
          }
          // You can retrieve as many field as you like as above...
        }
      }
    }
    

    I strongly recommend you making use of an object mapping library such as ObjectMapper so you don't have to worry about type checking or casting at all.

    Just create a model named Post:

    import ObjectMapper
    
    class Post: Mappable, CustomStringConvertible {
    
      var title: String?
      var slug: String?
    
      var link: URL?
      var content: String?
    
      required init?(map: Map) {}
    
      func mapping(map: Map) {
        title <- map["title.rendered"]
        slug <- map["slug"]
    
        link <- (map["link"], URLTransform())
        content <- map["content.rendered"]
      }
    
      var description: String {
        return "Post <\(title ?? "No title")>"
      }
    }
    

    so you can retrieve all posts as follows:

    import AlamofireObjectMapper
    
    Alamofire.request("http://www.wsvh.nl/wp-json/wp/v2/posts")
      .responseArray { (response: DataResponse<[Post]>) in
    
        // This will give you the array of Post objects.
        print("Posts: \(response.result.value)")
    }
    

    I've created an example project for you. You can download and play around with it to have a better understanding about how mapping is performed.