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
URLSessionand its constituent classes. In general
URLSession is responsible for sending and receivng
HTTPRequests. For basic requests you can use
sharedsession 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
URLSessionwith 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 using
Dataobjects. 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.
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
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
download(parameters: Parameters) etc. Example has only two cases to send plain request or with parameters.
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.
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
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
- Set httpMethod of the request equal to that of our
- Set headers.
- If parameters encoding is “json” and request has parameters — use
JSONSerializationto covert dictionary with parameters to Data. You can add try catch closure to handle the exception.
Next part done! Congratulations!
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
NetworkError. There are two cases:
.success- if success - returns Decodable model
.error- if error - returns error of type
For blogpost example
NetworkError has only two cases:
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.
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:
ProviderProtocolwhich 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
URLSessionProtocoland 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
- Initialise request from service object.
URLSessionDataTaskto 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.
handleDataResponsecompletionHandler 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
NetworkErrorenum and parse it.
- In this scenario all requests return a json data so if response is empty function returns error
HTTPURLResponsecontains status code of sent request. In this example requests with status code between 200...299 have success status in other cases failure.
JSONDecoderto 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.
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
Postmodel which conforms to Decodable and Encodable protocol.
3. Handle response! That’s all! :)
You can download the complete project for this tutorial here:
Contribute to marcinjackowski/NetworkLayer development by creating an account on GitHub.
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.