Skip to content
This repository has been archived by the owner on Sep 19, 2018. It is now read-only.

Error Handling

mdmathias edited this page Sep 15, 2016 · 7 revisions

Common Errors in Parsing JSON

Parsing JSON can be error prone. Two sorts of errors are especially common: 1) the JSON doesn't have the key that you are looking for, and 2) you are trying to subscript the JSON with an index that is out of bounds.

Freddy helps you mitigate these and other errors by leveraging Swift's native mechanism for error handling. This means that Freddy provides useful information should the JSON throw a curveball.

JSON's Errors

Freddy's JSON enumeration defines an ErrorType called Error that catalogues the errors that may be encountered while parsing a JSON instance.

extension JSON {
    public enum Error: ErrorType {
        case indexOutOfBounds(index: Int)
        case keyNotFound(key: String)
        case unexpectedSubscript(type: JSONPathType.Type)
        case valueNotConvertible(type: Any.Type)
    }
}

Below, we run through common examples of handling an error while working with JSON. Before we begin, let's define some JSON:

{
    "people": [
        {
            "Matt": 32
        },
        {
            "Drew": 33
        }
    ]
}

Here, we have JSON with a key "people" that points to an array of dictionaries, where each dictionary gives a person's name and their age.

Index Out of Bounds

  • indexOutOfBounds(index: Int) - the .indexOutOfBounds case tracks errors for when we try to index an JSON.array, but have supplied an index that is not within the array's range. The case's associated value will correspond to the index that is out of bounds.

For this example, imagine that we want to grab the third index in the array associated with the key "people" in the JSON. The trouble is, there is no third index...

let json = ["people": [ ["Matt": 32], ["Drew": 33] ] ] as JSON
do {
    let thirdDictionary = try json.getDictionary(at: "people", 2)
} catch JSON.Error.indexOutOfBounds(let badIndex) {
    print("Index out of bounds: \(badIndex)")
} catch {
    // Handle the catch all
}

Since the array only has two elements, the .indexOutOfBounds error will be thrown and caught.

Key Not Found

  • keyNotFound(key: String) - the .keyNotFound case is thrown when a JSON instance is subscripted for a key that is not present in the JSON. The associated value for this case will be the key that was not found.

Let's pretend that we are expecting to find data within the above JSON for our friend "Sarah". Since this key is not present within the JSON, we will get the keyNotFound error.

do {
    let sarahAge = try json.getInt(at: "people", "Sarah")
} catch JSON.Error.indexOutOfBounds(let badIndex) {
    print("Index out of bounds: \(badIndex)")
} catch JSON.Error.keyNotFound(let badKey) {
    print("Key not found: \(badKey)")
} catch {
    // Handle the catch all
}

The second catch for .keyNotFound will match here.

Unexpected Subscript

  • unexpectedSubscript(type: JSONPathType.Type) - this case is thrown when we attempt to subscript a JSON instance with a subscript of some unexpected type. For example, this error will be thrown if we try to subscript a JSON.dictionary with an Int. The associated value provides us with the type the JSON was not expecting.

What if we were expecting the JSON to simply return an array of people? If we wanted just the first person in that array, we might try to subscript the JSON with an Int. This will not match the JSON above, and will generate an .unexpectedSubscript error.

do {
    let people = try json.getArray(at: 0)
} catch JSON.Error.indexOutOfBounds(let badIndex) {
    print("Index out of bounds: \(badIndex)")
} catch JSON.Error.keyNotFound(let badKey) {
    print("Key not found: \(badKey)")
} catch JSON.Error.unexpectedSubscript(let badSubscript) {
    print("Unexpected subscript: \(badSubscript)")
} catch {
    // Handle the catch all
}

In this example, the third catch for .unexpectedSubscript will match.

Value Not Convertible

  • valueNotConvertible(type: Any.Type) - the .valueNotConvertible error is thrown when we attempt to convert a JSON instance into a type that it be cannot be converted to. For example, we will get this error if we try to convert an Int value into a String (e.g., json.getString(at: "age")). The associated value describes the type mismatch.

For this example, let's assume that we got our stars crossed and are trying to subscript "Drew"'s age as a String.

do {
    let drewAge = try json.getString(at: "people", 1, "Drew")
} catch JSON.Error.indexOutOfBounds(let badIndex) {
    print("Index out of bounds: \(badIndex)")
} catch JSON.Error.keyNotFound(let badKey) {
    print("Key not found: \(badKey)")
} catch JSON.Error.unexpectedSubscript(let badSubscript) {
    print("Unexpected subscript: \(badSubscript)")
} catch JSON.Error.valueNotConvertible(let badValue) {
    print("Value not convertible: \(badValue)")
} catch {
    // Handle the catch all
}

Here, the .valueNotConvertible error will be caught because the key "Drew" points to an Int, but we asked for a String.

Think About Your Path

Often times the root of the problem you are grappling with will be due to a bad path. You may think the path you are describing ends up at an Int, but it is really a String. For example, the line let people = try json.getArray(at: 0) fails because the path described by the subscript 0 does not lead to the anticipated array. This error can be corrected by supplying the correct path: let people = try json.getArray(at: "people").