Async Network Layer

Most iOS applications need to fetch data one way or another, Swift makes it pretty easy to achieve that. However, if your app has different data types of data, the code can get repetitive, this is a fantastic opportunity to consolidate this repeated code. I'll show you guys a way to achieve that!

The code for this article can be found on my GitHub.

Creating A Flexible Network Layer

Request Builder

The first thing we should do is create a request builder. Every time we need to fetch data we have to create new request objects, having a request builder can prevent us from having to duplicate code every time. it looks something like this:

No alt text provided for this image

These are the parameters are the typical parameters for a request: The URL is the endpoint that we are fetching data. The headers are the parameters for our API call. The body is the data to be uploaded to the server. request timeout is the time we want the app to wait for the data to come back. And the httpMethod is the type of request we are making. We also have the buildRequest function that builds the actual request that we can then use later to fetch our data.

The above struct uses a few helpers :

No alt text provided for this image

The enum HTTPMethod allows us to restrict the type of requests we want the API to support and also prevents invalid types to be passed into our request builder. The DataFetcherUtils enum allows us to have a static encoder and decoder, that way we do not have to initiate a new one on every request. Finally, the extension on Encodable makes it easier for us to encode the requests body.

Data Fetcher

Now, all we need to do is to use our request to fetch some data, to achieve that we can create a data fetcher.

The first thing I like to do is create a protocol, this will allows us to later mock this class for testing purposes. Our protocol will look something like this:

No alt text provided for this image

The request time-out parameter allows us to set a time limit that we are willing to wait for our data to arrive after we make the request, if the request is taking too long for any reason we will throw an error after that amount of time has passed. Our request function will be the function to retrieve the data, and the generic type 'ResponseType' will be the object we are expecting the endpoint to return, it needs to conform to Decodable so we can parse it later. the req parameter is the above-mentioned request structure and the decoder will be used to parse the data coming back from the endpoint.

Now, all we need to do is have an implementation of this protocol:

No alt text provided for this image

Because our fetcher is made to be used asynchronously, we want it to be thread safe. To achieve this we can make it an actor. We also want a default implementation that is static so we don't have to build a new DataFetcher every time we need to make a request.

the request function creates a session configuration so that we can set our request timeout, in this case, defaulted to 30 seconds. We then create an URL object using the requests URL string, throwing an error if the URL is invalid.

Once we have the URL we can then request our data from that URL, in this case, we are using the URLSession.shared to do this, but you can also make your instance of Session for this. The .data function in the session takes in our request and returns a tuple with data and a URLResponse.

Now, all it's left to do is to decode our response data and return our expected object!

Using Our Network Layer

I have created 2 examples of how to use our data fetcher, one example fetches animes from the "https://anime-facts-rest-api.herokuapp.com/api/v1" endpoint and the other one fetches animals from the "https://zoo-animal-api.herokuapp.com/animals/rand/10" endpoint. I'll not add the code snippets to how I constructed the views but you can view it on my GitHub.

To fetch the data from these endpoints becomes simple now, all we need to do is create a request, and make a decodable object for our response type:

No alt text provided for this image
No alt text provided for this image

Both the Anime and the Animals example follow the same pattern, we create our decodable model based on the data that we expect to receive from the API, create a request with the endpoints URL and fetch the data! Our app now looks like this:

A Step Futher

We already have a fully working, however, we can abstract it a little further. Most endpoints return JSON formatted data these days, but not all. At the moment the data fetcher only supports JSON formatted data, however, we can change that by simply making two more protocols like this:

No alt text provided for this image

This will allow us to create our decoders and encoders if necessary, notice that JSONDecoder and encoder now implement these protocols as well. This way we can pass in custom encoders and decoders into our request struct and our request data function like this:

No alt text provided for this image
No alt text provided for this image

I hope this was helpful and you guys enjoyed the reading! :)

To view or add a comment, sign in

More articles by Inti Albuquerque

  • Draggable Views In SwiftUI

    Recently, while working on a feature that involved rearranging views through drag-and-drop on the screen, I developed a…

    3 Comments
  • Custom String Interpolation in Swift

    When creating an app, almost everyone will have to display texts to their customers. This normally requires lots of…

  • Organizing Assets In Your Project

    Assets can get pretty messy when your iOS project starts to grow, repeating the name of the asset every time you need…

    2 Comments
  • Truncation Tex Field SwiftUI

    In my previous article, I wrote how to make a focusable text field in SwiftUI. However, upon further testing, I found…

  • Continuous Streaming With Combine

    Combine is a powerful tool to deal with streams in IOS, it keeps streaming data until it either errors out or is told…

  • Identifiable and Selectable Collection

    This week I came across an interesting problem creating a new screen. When you have objects that need to be uniquely…

  • Creating A Functional Text Field In SwiftUI

    Last week I came across a problem when creating a screen, where a user could navigate through multiple text fields…

    1 Comment

Others also viewed

Explore content categories