Network Layer in Swift 4.0
Every time when i start a new project there is the same question. How to implement a network layer? To use external libraries like Moya, Alamofire etc. or to write it from the scratch.
My answer for this question is — Use pure Swift without any third-party libraries. It’s a super simple to implement protocol-oriented layer, type safe with enum to configure endpoints and fully testable, of course. In these few points you will learn how to write protocol oriented networking layer that you can customise.
First things first
Before you start, it’s important to understand URLSession
and its constituent classes. In general URLSession
is responsible for sending and receivng HTTPRequests
. For basic requests you can use shared
session which has no configuration object. It’s not as customisable as sessions you create by yourself, but it serves good starting point if you have very limited requirements. For other kinds of sessions, you instantiate a URLSession
with one of three kinds of configurations:
.default
- session behaves as a shared session, but allows more configuration and to obtain data incrementally with a delegate..ephemeral
- session is also similar to shared session, but don’t write caches, cookies, or credentials to disk..background
- session let you perform uploads and downloads of content in the background while your app isn't running.
URLSession returns data in two ways:
- completion handler
- calling methods on a delegate
Within a session you can create URLSessionTask
to retrieve data from the server, upload photos or download files. Moreover you can also resume, suspend and cancel tasks. URLSessionTask
gives opportunity to pause running task for example when user leaves app and resume it when returns. The URLSession provides three types of tasks:
data
- sends and receives data usingData
objects. Data tasks are intended for short, often interactive requests to a server.upload
- similar to data tasks, but in general used to upload files and support background uploads while the app isn’t running.download
- retrieve data in the form of a file and support background downloads and uploads while the app isn’t running.
In this tutorial you will use only first type of URLSessionTask
to send request and handle response form the server.
Ok after a short recap of what URLSession
can do and now let's do some practice.
ServiceProtocol
First you have to divide network layer to a small services. Keeping all requests in one class/enum is difficult to maintain and might transform into a monster massive thing. ServiceProtocol
will be helper to create URLRequest
. ServiceProtocol
contains constituent components such as baseURL, path, method, headers, task and parametersEncoding. Go ahead and create your first file of simple networking layer.
HTTPMethod is an enum responsible for setting HTTP method of requests. URLRequest has property .httpMethod
to set method String type.
Task is an enum responsible for configuring parameters for a specific service. You can add as many cases as are applicable to your network layer requirements. For example upload(Data)
, download(parameters: Parameters)
etc. Example has only two cases to send plain request or with parameters.
ParametersEncoding
ParametersEncoding
is an enum responsible for setting encoding type. In this example you have to use the most popular: URL and JSON.
Voilà! First part of creating network layer is done. Keep your head up and keep going! Let’s move to the next part — How to implement constructor of URLRequest.
Request
Before you send first request to the API you have to create custom request from ServiceProtocol
. As you probably noticed Service has all information to construct Request. To avoid creating new class you will create an extension to URLRequest
and URLComponents
.
First of all: create URLComponents
file. This extension will merge baseURL with path and will add parameters to the url if parameters encoding is url. Paste this code to your file:
- To get full path of url you need to append path to base url..
- Using your new url, you initialise a URLComponents.
- If parameters encoding is “url” and request has parameters — create array of [URLQueryItem] for each parameter and set to the queryItems.
Next step is URLRequest
. Create file and add the following implementation:
- First create urlComponents.
- Using your new urlComponents initialise a
URLRequest
. - Set httpMethod of the request equal to that of our
ServiceProtocol
. - Set headers.
- If parameters encoding is “json” and request has parameters — use
JSONSerialization
to covert dictionary with parameters to Data. You can add try catch closure to handle the exception.
Next part done! Congratulations!
NetworkResponse
When you get response from sent request, completion handler returns unreadable information. Optional data, response and error says nothing. You have to create enum to handle response from API and display clear message. Create two files NetworkResponse
and NetworkError
. There are two cases:
.success
- if success - returns Decodable model.error
- if error - returns error of typeNetworkError
.
For blogpost example NetworkError
has only two cases:
URLSession
You have almost finished network layer. Last thing which need to be implement is a provider to send requests. To do that create new file ProviderProtocol
and add the following implementation:
ATTENTION!: T must conform to Decodable protocol.
If ProviderProtocol
is done, now you can start implementing last class URLSessionProvider
which is the heart of your network layer. To do that: create new file and copy following code:
URLSessionProvider
conforms toProviderProtocol
which has been created few lines earlier.- This approach is necessary to test network layer. It’s essential because in easy way you can switch session with mock file and simulate responses from API without internet connection. With the next blogpost i will explain you how to test network layer. For now please create a new file
URLSessionProtocol
and copy following code:
Next you will create request function. This function is responsible for all the vital work in our network layer. Add this method to URLSessionProvider
.
- Initialise request from service object.
- Create
URLSessionDataTask
to send and receive data from API. Data tasks are intended for short, often interactive requests to a server. - Start task. Session will send request to the server and wait for the response.
handleDataResponse
completionHandler returns optional values and you actually don't know if request has finished with success or error. You need extra method to parse response data and error.
- First you have to check if an error has occurred. If your API return some information in error, add custom init to the
NetworkError
enum and parse it. - In this scenario all requests return a json data so if response is empty function returns error
HTTPURLResponse
contains status code of sent request. In this example requests with status code between 200...299 have success status in other cases failure.- Use
JSONDecoder
to decode response data and return expected object with type T.
That’s all! Your network layer is completed in pure Swift, no third party libraries. In next part you will find out how to create simple service and send first request.
Demo
In this demo you will use free API (https://jsonplaceholder.typicode.com) which allows to fetch posts, comments and users info. First of all create file PostService
and copy following code:
PostService implements two cases: fetch all posts and comments for specific postId. For both cases you use “GET” method and “url” parameters encoding. Case “all” doesn’t require any special parameters so you can use plain request but for “comments” case you need to send request with parameters (key: “postId”, value: Int).
Finally you are ready to send your first request and use implemented provider! Open ViewController
and add the following method:
- Create property to have strong reference to the provider.
- Send request with specific type. In this case you want to fetch list of posts so add
Post
model which conforms to Decodable and Encodable protocol.
3. Handle response! That’s all! :)
You can download the complete project for this tutorial here:
Conclusion
As you can see to build networking layer it’s not necessary to use third-party library with complicated logic. The biggest advantage of this solution is that it’s written in pure swift. To You can download the complete project for this tutorial here.