-
Notifications
You must be signed in to change notification settings - Fork 119
Error Handling
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.
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.
-
indexOutOfBounds(index: Int)
- the.indexOutOfBounds
case tracks errors for when we try to index anJSON.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.
-
keyNotFound(key: String)
- the.keyNotFound
case is thrown when aJSON
instance is subscripted for a key that is not present in theJSON
. 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.
-
unexpectedSubscript(type: JSONPathType.Type)
- this case is thrown when we attempt to subscript aJSON
instance with a subscript of some unexpected type. For example, this error will be thrown if we try to subscript aJSON.dictionary
with anInt
. The associated value provides us with the type theJSON
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.
-
valueNotConvertible(type: Any.Type)
- the.valueNotConvertible
error is thrown when we attempt to convert aJSON
instance into a type that it be cannot be converted to. For example, we will get this error if we try to convert anInt
value into aString
(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
.
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")
.
Created by Big Nerd Ranch 2015