9

take the following JSON:

let rawJson =
"""
[
      {
          "id": 1,
          "name":"John Doe"
      },
      {
          "id": 2,
          "name":"Luke Smith"
      },
 ]
"""

and User model:

struct User: Decodable {
    var id: Int
    var name: String
}

It's pretty simple to decode, like so:

let data = rawJson.data(using: .utf8)
let decoder = JSONDecoder()
let users = try! decoder.decode([User].self, from: data!)

But what if the JSON looks like this, where the top level is a dictionary and need to fetch the array of users:

let json =
"""
{
    "users":
    [
        {
          "id": 1,
          "name":"John Doe"
        },
        {
          "id": 2,
          "name":"Luke Smith"
        },
    ]
}
"""

What's the most effective solution to reading the JSON? I could definitely create another struct like this:

struct SomeStruct: Decodable {
    var posts: [Post]
}

and decode like so:

let users = try! decoder.decode(SomeStruct.self, from: data!)

but it doesn't feel right doing it that way, creating a new model object just because the array is nested inside a dictionary.

1
  • 1
    Check this article under the "wrapper keys" heading. It appears this is the correct way to parse that structure out. benscheirman.com/2017/06/… Commented Oct 10, 2017 at 15:27

1 Answer 1

6

If you want to take advantage of JSONDecoder you have to create a nested struct(ure).

I recommend to use the name Root for the root object and put the child struct into Root

struct Root : Decodable {

    struct User : Decodable {
        let id: Int
        let name: String
    }

    let users : [User]
}

let json = """
{
    "users": [{"id": 1, "name":"John Doe"},
              {"id": 2, "name":"Luke Smith"}]
}
"""

let data = Data(json.utf8)
do {
    let root = try JSONDecoder().decode(Root.self, from: data)
    print(root.users)
} catch {
    print(error)
}
Sign up to request clarification or add additional context in comments.

2 Comments

There is no need to have the User struct nested into it the Root struct struct User : Decodable { let id: Int let name: String } struct Root : Decodable { let users : [User] } The result would be the same
Yes there is no need, but if the struct is not used somewhere else it's cleaner (imho) and it illustrates the equivalent of the JSON structure.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.