As an iOS developer, parsing JSON is undoubtably something that you will have to do. With the growing number of APIs available, the ability to parse JSON and use that data in your app has never been more useful. I will show you how to parse JSON data and use it within your app in a few easy steps.
Setting up the structure (with standard types)
Firstly, you need to figure out what data you will get back from the API call so that you can setup your structure in Swift. Most websites will show you an example API call or even provide you with the structure you will need, along with the data types.
In this example, I will consider an API that provides information about movies. We will consider a Movie
structure that holds basic details about a movie. To make this structure encodable and decodable, we will conform to the Codable
protocol.
struct Movie: Codable {
let title: String
let releaseDate: String
let runtime: Int
let ageRating: String?
let posterUrl: String?
}
Note: Notice that some of the properties are optionals; this is because the API call may return them as null, in which case the app would crash if they were not optional. You can usually figure out which properties need to be optional by looking at the API documentation and example API calls.
Setting up the structure (with custom types)
Most calls will have at least one property that is an array or dictionary. We can use custom types to deal with these cases.
I will expand the example above by adding a list of the cast members of the movie, which will be represented by an array of another structure, CastMember
.
struct Movie: Codable {
let title: String
let releaseDate: String
let runtime: Int
let ageRating: String?
let posterUrl: String?
let cast: [CastMember]
}
struct CastMember: Codable {
let name: String
let character: String
let imageUrl: String?
}
Result type in Swift
Our API call will ultimately return a Result type, which was introduced in Swift 5. Essentially, it is a value that represents a success or a failure; if in our case there is a success, a Movie object will be returned. If there is a failure, an error will be returned. In order for an error to be returned, we need to make our own custom error that will let the user know what went wrong.
To make a custom error, we will make a simple enum with a few cases, reflecting the type of network errors we can receive. You can learn more about enums here.
enum CustomError: String, Error {
case invalidResponse = "The response from the server was invalid."
case invalidData = "The data received from the server was invalid."
}
Setting up the function
Now that we have our structure ready, we can make our API call and use a JSONDecoder
to decode the data received from the API into our structure.
To start with you need to find the endpoint of your API call, which will be a url with the different parameters depending on what information you want to receive. Most API's will require you to get an API key.
let endpoint = "https://movies/movie/138807?api_key=somekey1234583902"
Your url is currently a String so you need to convert it to Swift's URL
type before you can make the call. A simple guard
statement can be used for this.
guard let url = URL(string: endpoint) else {
completed(.failure(.invalidId))
return
}
Providing there is no error, a URLSession
can be started. In this closure, we have access to data
, response
and error
.
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
...
task.resume()
}
We can check for an error using an if let statement and then check for data using a guard let statement. If there is an error, the completion handler will be called with .failure
and that will be the end of our function.
if let error = error {
completed(.failure(.unableToComplete))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
At this point, it is time to use our Movie
structure to decode the data received.
do {
let decoder = JSONDecoder()
let movie = try decoder.decode(Movie.self, from: data)
completion(.success(movie))
} catch {
completion(.failure(.invalidData))
}
If everything has been successful, our completion handler will return the Movie
object that has been decoded from the data.
Calling the function
The function making the API call has now been completed. To access the value from this call, we can use a switch statement to check for whether there is a result (.success) or an error (.failure).
getMovie() { result in
switch result {
case .success(let movie):
print(movie)
case .failure(let error):
print(error)
}
}
I hope this article was useful for understanding API calls in Swift; feel free to leave any comments and any tips would be highly appreciated!
Top comments (0)