Swift Generics: How to build a clean network layer
source link: https://sweettutos.com/leverage-swift-generics-to-build-a-modular-network-layer/?amp%3Butm_medium=rss&%3Butm_campaign=leverage-swift-generics-to-build-a-modular-network-layer
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Swift Generics: How to build a clean network layer
Codable, URLRequest, Result type. These are the main terms that sounds familiar whenever you deal with network in Swift. Networking has always been an important part of every mobile app, thus a well designed network layer is key to a successful app.
Usually when we refer to modularity, network layer works best when it is implemented as a separated module that behaves as the gate for your app to the outer world.
As a rule of thumb, a network module’s main responsibility is to send a request to an external resource, receive the response and give it back to the caller module.
The network module itself can be break down into several components. In this post, we will walkthrough all the parts that contribute to building a networking layer.
HTTP method
This is what specify the HTTP request method, the most common verbs are GET, POST, PUT, PATCH, and DELETE. We can wrap this up in some enum type object. Something like this:
The callAsFunction
allows to apply a function call syntax on the HTTPMethod enum type to return the raw value.
Routes
Route is part of the URL and represents the path we use to access the endpoints. As done with HTTP methods, it is a good practise to group all routes in one place.
HTTP errors
As the request may fail, error handling is a crucial part in a networking layer. A simple request that fetch and decode data from the network may fail for the following reasons:
The names above are self explanatory, but they will make more sense when we finish drawing the next parts of the layer
Scheme and host
The scheme and host are what identify the protocol and the resource name respectively. In the case of https://www.google.com
the scheme is the https
while the host is what comes after. The host can be longer if it is a subdomain – In general, it is what comes between the scheme and the resource path.
For clarity reasons, we can encapsulate these two informations in a struct type, like below:
The HTTP Client
The main components of a request are explored above, now is the part where to build a simple client that will take the request, send it over to the network and then send back the received response.
Imagine, we have an app that deals with posts – Few actions we can think about are the following:
- GET posts list
- GET authors list
- GET post details
If we gonna implement each of the following requests, we can think of 3 methods, one for each action:
GET posts list:
GET authors list:
GET post details:
All the above methods signature is pretty much the same, except the return type that changes – As you may think, the methods will also have almost the same implementation. As a result we will have duplicated code that does the same think: Send a request and parse a response.
So why not we prevent this code duplication?
Remember in a previous article we used generics to dequeue table view cells – And Generics come to the rescue again. Assuming that all types (Post and Author) conforms to the Decodable protocol. Here is our Post model for instance:
As a result, all the methods above can be replaced with one single method, its signature can be as follow:
The type placeholder here is a Decodable. The implementation can be unified as follow:
As you can see, we now have a method that sends ALL types of requests and parses ALL types of data as long as this data conforms to the Decodable protocol. Super handy, no code duplication and a straightforward method.
You may also notice that we started using the HTTP errors defined earlier as part of the failure completion callbacks.
The final piece
The network layer is pretty much done, our app needs some sort of interface to interact with it in order to hit the network.
We can define a class that acts as the point of contact between the network layer and the rest of modules in our app – Consider the following:
The class definition is pretty basic – It has two dependencies in order to instantiate an object: APIConfig and HTTPClient types dependencies.
The getPosts(completion:) method will be called to fetch posts from the endpoint and return an array of Post objects. This method is responsible of building up the request. In this example the request is a simple GET request but in some cases it may require some path and/or query parameter(s). In such cases, this method is the right place to append those parts to the request.
Wrap it up
That’s pretty much it. You now have a complete basic functional networking layer that is easily scalable to implement more tasks.
A simple usage example of our layer would be something like this:
The above code can be put in a UIViewController and called in the viewDidLoad.
Always remember to separate your network layer in an isolated component – Whether it is a framework or a simple class. The point is, make it clear to you and your fellow peers what will this layer task be among your app modules with a clear interface and a single responsibility approach.
Here is a link to download the sample project.
What are the patterns that you usually follow when building your networking layer? Let me know on Twitter.
Thanks!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK