In today’s app development, we do a lot of stuff with APIs AKA Network calls in the application. We normally do the network calls with Apple’s `URLSessions` or other third party libraries like `Alamofire`. In this post, we are going to see how we can abstract the networking layer by creating a generic API manager with the help of Apple’s Combine Framework.
Pre-requisites: Basic understanding of Combine. Knowledge on Publishers, Subscribers, Operators. Refer this
Let’s get started…🏁
For this article, I’m going to fetch user details using randomuser.me API. This is a simple project which just does a data task, fetch user details and display it in a list. I’m doing this in the MVVM design pattern.
Check out the repo here.
There are three steps to achieve it.
- Create APIManager
- Create a ViewModel
- Create View to render the API result
Create a file named “APIManager.swift” and inside that a class with the same name.
In APIManager class there are six points to understand.
fetch function is created with two params, URL and completion. where ‘T’ is the generic type(model) we are going to use. It can be any struct confirming ‘Decodable’ protocol.
- dataTaskPublisher — This is a Publisher which gets URL as an input and provides an output of tuple (data: Data, response: URLResponse). Here, we captured the data from it.
- Next, use ‘map’ operator to get the data, we got from step 1, and pass for decoding
- Decode the data using .decode() operator with JSONDecoder object.
- Doing the steps in the main thread using receive(on:) method
- Passing the decoded value to completion block using, sink(receiveCompletion:receiveValue:) method (subscriber). In this step, receiveCompletion will throw if there is an error in the process and receiveValue will return the decoded output value
- Finally, the subscription needs to be saved in an ‘AnyCancellable’ Set.
Thus, we have completed the APIManager class. Next step is to create the ViewModel.
Create a ViewModel
First, we need to create a model.
For this demo, I’m just fetching the name, email and phone values from the API data.
Here, I have created a UserViewModel struct confirming Identifiable protocol (in order to list) and UserListViewModel class which is an ObservableObject to publish the fetched values.
In UserListViewModel class,
- @Published variable created which gives the array of UserViewModel
- An object of APIManager class has been created
- fetchUsers(endPoint:) — in this method, endPoint is nothing but an enum storing the URL. Inside the method, apiManager.fetch() method has been called. In the completion handler, we are providing the type of the result as Result<UserResults, Error>. Based on the result we are handling the .success and .failure cases.
Create View to render the API result
Finally, Let’s render the output in the view. Create a View struct named UserListView.
In this step,
- @StateObject created for UserListViewModel
- ProgresssView will get displayed if there is no data fetched
- Once the data task completed the data will get published by the userViewModels var of userListVM.
- Published values are listed out in a SwiftUI’s List view.
Now, we have abstracted the network layer with the help of Combine Framework. In this post, I have done a single API only. Likewise, we can pass any Decodable model struct and fetch the value from an API.
Try some other API on your own.
Thanks for reading. 🙏
Happy Coding 💻 😊