DEV Community

grigor-dochev
grigor-dochev

Posted on

How to parse JSON Data from API with Swift 5

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?

}
Enter fullscreen mode Exit fullscreen mode

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?

}
Enter fullscreen mode Exit fullscreen mode

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."

}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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()

}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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))
}
Enter fullscreen mode Exit fullscreen mode

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)
    }

}
Enter fullscreen mode Exit fullscreen mode

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)