How to handle null JSON values in Swift

A Parsing JSON in Swift reader recently wrote in and asked:

I did have a question regarding getting a null value in your JSON. I know null is different than a nil value so I didn’t know how to go about safely receiving it?

So what do you do if you get a null value in your JSON? How do you handle it safely, without causing your app to crash and burn?

The first question to ask is this: how important is that value you’re trying to get? Do you absolutely need a value for it? If the property is an id, it’s likely that you do need it to be non-null in order to transform it into a Swift object.

We’re going to parse a repository today, and we’re going to say that a repository with no id is no repository at all.

struct Repository {
    let id: Int
}

Another reader, also wondering how to handle nulls, says this:

I am not sure the best way to do this without having many if let statements

So do we need a bunch of if let statements like this?

func parseRepository(json: JSONDictionary) -> Repository? {
    if let id = json["id"] as? NSNull {
        // don't create the object, 'cuz we can't have a Repository without an id
        print("Got a null id. Check it out: \(id)")
        return nil
    }
    
    if let id = json["id"] as? Int {
        // hey hey -- we got the `id` we needed!
        // TODO: parse the rest of the JSON...
        print("parsed id: \(id)")
        return Repository(id: id)
    }
    
    return nil
}

Here, we start by checking whether the "id" in our JSON is null — and if it is, we’ll bail early, returning nil from our method. But then we still need to create the id with the type we want in a second if let statement.

So while we have the id we need — and it’s the right type (Int) inside the second if let block, you may be thinking…

Would we have to nest all the rest of our parsing code inside the second if let block? Yep.

This’ll be pretty ugly when we have other properties in our JSON that we also want to be non-null, since we’d two if lets for each of them. Yep.

And then we’d have to continue nesting our if lets deeper and deeper. Yep.

There has to be a better way. Is there a better way? Yep.

Behold, a better way:

func parseRepository(json: JSONDictionary) -> Repository? {
    guard let id = json["id"] as? Int else {
        print("Couldn't convert id to an Int")
        return nil
    }
    // TODO: parse the rest of the JSON...
    return Repository(id: id)
}

This handles all of it. No nesting required. And more importantly, it does what we need it to. If the value of "id" is null in our JSON, parseRepository returns nil. If "id" is a string, parseRepository returns nil. If "id" is an object, parseRepository returns nil. And if "id" is an integer, we’ll continue parsing our JSON and eventually return a Repository if all goes well.

You can be absolutely sure of all those things by writing unit tests for your JSON parser. Write your first test in less than an hour with Parsing JSON in Swift.

Grab the playground below to see all the code and tweak it to handle your JSON.