The network layer with respect to a mobile application development could be summed as the combination of all the components that help you create, authenticate and trigger a request and process the response.
In this blog, I will share my experiences in building a network layer from my past projects. We will discuss the reasons behind the approaches involved.
How does an API connection look like?
The device sends a request and receives a response that is the data from the server after processing the request.
An API request typically consists the following components:
a) Request type
b) Request URL
d) Request body
API response comprises the data that your server provides you after processing your request. The content of the responses data can be of different types that you can specify while making a request. More can be found in this link.
So without digging any further let us jump straight to configure the network layer.
Let us hop in !!
What will we discuss?
Let us look at what are the few things we would like to achieve:
- The network layer should be modularised and each module should have a single responsibility.
- The callee of APIs should be given back the control of the requests if in case it wants to handle any specific requirements, eg. canceling requests if needed.
- End paths of APIs should be maintained and represented properly.
- Looking at the network layer could give us an idea about what all are the APIs for a particular category. Eg. There might be many APIs related to customers that the application might use, like fetching all restaurants, restaurant detail fetch, etc. These all should be cumulated in a single place.
- Every API should have the responsibility to provide its additional headers, request type, and API end path and the base path even.
- It should be able to handle additional headers if any API has a requirement for.
For our discussion, we will be taking the help of GoogePlacesAPI. Our sample application will show a list of restaurants nearby to your current location within 200 meters.
Now let us look that how we can break down our network layer to keep it simple and testable
Common protocols, enums and model classes
API as enum cases
What could be more elegant than maintaining similar APIs under a common category. This would help us categorising our APIs. So why not do it via enum. Let us take a look at our RestaurantsAPI enum.
You can find that it conforms to a protocol, APIProtocol. So what is it? Well that’s next to find out
This protocol composes methods which have to be implemented by any API enum as shown below. This way of implementation provides us an excellent way to add additional capabilities to our APIs.
An actual model of ours consists of an APIProtocol type and parameters associated with it if there is any.
Struct which represents a complete API conforming to the APIModelType.
Well confused !! We will soon be well acquainted with all of them.
We can break the network layer to the following modules:
a) Request module
b) Configuration module
c) Sessions module
d) Helper module
The request module comprises the request classes. Request classes are the classes that hold a similar type of APIs in them. Eg. Restaurant related APIs could be clubbed in a particular request class called the RestaurantServiceRequests classes, this class could hold the APIs for customer creation, updation, deletion, etc. Let us see how a request class looks like
So what’s going on here:
We have created a RestaurantServiceRequests.swift file in which we have a structure RestaurantServiceRequests. RestaurantServiceRequests has all the APIs related to restaurants. Every APIs return a DataTask instance so that the callee could have control of the requests if they need to process anything depending on the state of the request.
Responsibilities of this module:
- It holds request methods.
- It holds the data parsing logic i.e converting raw response data to models.
- Since the functions are independent of one another, you could even add more functionalities to the same eg. saving the data to the database if needed.
- You could also create a service request class for each API if you want more segregation.
Sessions module holds the singleton sessions manager. Usually we have URLSessions session manager or if we are using any third party eg. Alamofire, you have AlamofireSessionManager shared instance for that.
You could also create your own custom sessions manager if you want to have more control on the way your api sessions work. But that is out of the scope of this blog.
The configuration module is the module that configures your request. It creates the request URL, adds required headers and parameters to the request. Responsibilities of this module can be cumulated as:
- Creation of request URL by merging base path and API end path. Any additional validations and transformations to the URL can be performed here.
- Extracting parameters from the API model and adding to the request.
- Adding common headers or any additional headers specific to the API.
N.B If there is any key which is common to both the common header and additional header, which one to add in priority is up to your requirement.
The helper module takes care of the actual triggering of the request to the sessions manager. Responsibilities of this module:
- Calls the configuration module to create the request.
- Authorization validation if any is needed.
- Performs the actual triggering of the API calling the Sessions Manager.
Network Layer Schema
You can check the implementation of this Network Layer by downloading the sample code on GithubLink.
I would love to hear from you
You can reach me for any query, feedback or just want to have a discussion by the following channels:
Please feel free to share with your fellow developers.