Building a safe, modularized, and well-structured Networking Layer in Swift 4.2

Using DRY and SOC principles to improve your networking layer.

Medi Assumani
6 min readMar 8, 2019

Overview

Almost every dynamic iOS application has the ability to communicate with outside services(APIs) to be fully functional. To illustrate, the famous Google Translate iOS app communicates with a server to receive and send a word to be translated. This is done with the power of Networking. In this article, I will focus on modularity, reusability, maintainability, and extendability of a networking layer to avoid having monolithic ones like this…to only make ONE request!

What’s a Networking Layer?

A networking layer(domain) is a well-structured chunk of code used to make API requests and handle its responses from an external server. In Swift, Apple has implemented a handful of classes, structs, and functions for iOS developers to deal with networking. One of them is the URLSession class that encapsulates functions to help us download, upload, and fetch data from external APIs. Now that you’ve gotten a big picture of what a networking layer is, let’s start building one. We will be using the Product Hunt API for this exercise. I will assume that you’ve created an account and received your API and Secret key.

Request, response, parameters, and headers

Before we dive deep into this article, there are a few backend web concepts you must be familiar with as an iOS developer. In the Client-Server architecture pattern, the client makes a request to the server and the server sends back a response to fulfill the request. In our case, the client is your iOS application that makes requests to some API (an API is the part of the server that interacts with other applications). Within a request, we have parameters and headers. Parameters are just key-value data that tell the API more about the request being made. For example, if we wanted to get all the posts from Product Hunt API in descending order, sorted by vote count, and 20 posts per page, we will send them as key-value parameters. Lastly, headers are just extra metadata on top of headers that tell the API more about our request. To illustrate, if you were to make an authenticated API request or let the server know you are expecting data to come in a JSON format, you might want to pass the token(bearer, API key) and the content-type inside the header. Here is an example:

The Folder/File Structure

The structure of your files and folders will tremendously improve the readability of your project. In the root folder of your project, create a group (folder) and name it Networking. Inside, create three subfolders named: HTTP, Encoding, and Service. Your folder structure should look like the screenshot below. The reason why this is a good practice is that files will be easily found since the group names directly describe what they are.

The folder structure

Constructing the HTTP Folder

This is where all of our HTTP related operations, functions, enums, and structs live. We will start by creating an enum that will contain all the needed routes/endpoints/paths. Create a file named HTTPNetworkRoute(or Routes if you prefer). that will contains all the necessary endpoints needed for our app.

Next, we will create a file named HTTPMethod.swift that will contain an enum to encapsulate the different HTTP Methods we/you might make throughout the development of your app.

Following that, we will create an enum, HTTPNetworkError, that will encapsulates the most common types of networking errors. This will help us handle those errors easily and have friendly and customized messages to explain the error instead of having the generic and complicated Xcode error messages. You can add or remove cases as you please.

The next two things we will do under the HTTP folder are building requests and handling responses. Create one file named HTTPNetworkRequest that will contain a struct with methods to configure our requests, parameters, and headers. Moreover, we will create two typealias to easily declare parameters and headers types. If you are not familiar with the throws keyword, read this to help. The HTTPNetworkRequest struct contains two main functions: one to set up the request and the other to set up the parameters and headers if any.

Since we have created a struct to handle our request, let’s now make one that handles the response. Create a file named HTTPNetworkResponse that will contain an enum with cases and methods to handle the API response swiftly😉. If you are not familiar with HTTP Response status codes, check this out.

Encoding

From Techopedia:

Encoding involves the use of a code to change original data into a form that can be used by an external process.

In order to build safe networking layers, we must make sure that our URL and requests are built safely and thoroughly. Swift encapsulates handy functions that can help us accomplish this task. The main idea here is that a request and its components (URL, parameters, headers, body, etc…) must be converted in a certain format before being sent out. Create a folder named “Encoding” that will contain any type of networking encoding. Create a file named URLEncoder.swift, which will define a struct named “URLEncoder” which has two important methods: encodeParameters and setHeaders. As your app grows and needs to deal with multiple API requests, it is good practice to safely create your request. You can learn more about this here.

The Result

Before making our request, we need to know what type of results we will return at the end. The enum below tells us that after our network request with URLSession is done, we might either get data(success) or get an error(failure). If you are not familiar with Swift Generics, take a look at this.

Making the Request

Create a folder named Service within the Networking group. I prefer to name them resources because if you’re dealing with user, posts, comments, or likes, each of them can have a file (e.g: UserServices or PostServices) that have CRUD functions usually encapsulated within a struct or class. Look the snippet of code below and see how clean and uncluttered that is. We have separated classes and functions that take care of the request, response, encoding, handling errors, etc… This is a software engineering concept called “separation of concerns”.

Conclusion

As you can see, our network layer can adapt to different scenarios that can be encountered when dealing with external services. Whether we are getting, sending, updating, or deleting data, we can reuse the same classes over and over again without recreating everything.The code for this article can be found on my Github. Massive thanks to Malcolm Kumwenda for his fantastic article on Networking Layer that inspired this article.

About the Author :

Medi Assumani is currently a Computer Science student at Make School and iOS Developer in San Francisco, CA. You can get in touch with him through his email, LinkedIn or Portfolio.

📝 Read this story later in Journal.

🗞 Wake up every Sunday morning to the week’s most noteworthy Tech stories, opinions, and news waiting in your inbox: Get the noteworthy newsletter >

--

--

Medi Assumani

iOS Engineer @ Doordash. Writing about Mobile development and software engineering in general. Views and contents here are my own, of course.