Build your first SwiftUI app (Part 6): Creating the API helper class
Congratulations! We have already implemented many essential components of our first SwiftUI app. In the previous part, we applied the necessary logic for our authorization. In our LoginAction
class, we have everything we need to send an API request to our mock server.
Let’s think about scalability for a moment. If we wanted to create another API request, we would have to repeat most of the code we already wrote in our LoginAction
. That’s not the kind of architecture we want to have.
According to the DRY (don’t repeat yourself) principle, we should not duplicate code, and we should strive to encapsulate as much common code as possible to make the development easier for ourselves and anyone else who might work on the project with us in the future.
This class should cover all the API use cases we might need. This means we also want to handle other types of requests besides GET
. We want our class to be able to send POST
, PUT
, PATCH
, and DELETE
requests as well.
And that’s precisely what we will do now!
Basically, once we’re done with this helper class, it will be generic, meaning we won’t need to change it — or we will do it very rarely. Our Actions will use it instead by providing the necessary parameters to it and parsing the API responses from it.
Time for action! 😁
Create the APIRequest class
Let’s create a new singleton class in our Utilities
folder. We will call it APIRequest.
We will start shaping our helper class by moving the relevant code from our LoginAction
to APIRequest
. It will look like this:
So far, so good! Now let’s modify our LoginAction
to use the newly created APIRequest
class:
Great! Now our LoginAction
only contains the logic that is specific to, well, the login action. 😃 All the generic API-handling code is moved to the APIRequest
class, which can stay unmodified and be useful to us whenever we need to send an API request. And we have support for all sorts of API requests, and not just for theGET
request.
With this setup in place, if we need to make a new request, we can simply instantiate a new APIRequest
and fill it with parameters specific to that particular API call.
This is a significant first step. But our APIRequest
class is not powerful enough yet. We can extend it further to really make it shine.
Making it shine
First and foremost, our scheme and host variables don’t belong in the APIRequest
class. These variables should reside in a separate configurational file. So, let’s create a new file in our Utilities
folder, and name it Config:
Next, we’ll modify the APIRequest
class accordingly:
You can see that we are keeping things flexible by allowing passing scheme and host variables as parameters. Still, they are set to our hardcoded variables in the Config
file by default so that we can omit them from our calls.
Our API handler can handle the success cases, but what about failures? Currently, we are just printing the error message in the APIRequest
class, and that’s not a good way to deal with failures. Let’s improve this now.
Handling errors
We could use Apple’s Error
class for our error-handling purposes, but we’ll benefit more from creating our own class (that implements the regular Error
class). In the Utilities
folder, create a new enum and call it APIError
.
At this point, it will be straightforward and contain only two error cases:
Now, let’s integrate failure cases in our APIRequest
class. I marked the added lines of code with comments, so you can spot what was added.
Of course, now we need to integrate our custom errors in the LoginAction
class too:
Almost there! Let’s correct our LoginViewModel
now by adding a failure block and a variable that will hold our errors.
Finally, we need to show an error label to the user if the login action fails.
This requires adding a small code snippet to the LoginScreen
that displays an error label if the value of the error variable from the view model is set.
And that’s it! We didn’t change a lot of code, yet we implemented a solid base logic for error handling in our app. Now you can extend the APIError
class with your own custom cases to signal all potential error use cases in your app in a granular, precise way.
Enhancing the APIRequest
Our helper class is pretty powerful at this point! However, we can add a couple more things to our APIRequest
to improve it further.
Let’s start by implementing network availability detection. We need to create a new class in the Utilities
folder called NetworkMonitor.
This simple helper class will monitor the network status and put the result in the isReachable boolean variable. To make it work, we need to call its startMonitoring()
method as soon as possible.
Therefore, the best place to put this call is in the init()
method of the App class of the project. We need to modify our SwiftUIBlueprintApp,
so it looks like this:
Great! Now, let’s add our new error case in the APIError
we created earlier:
Finally, all there is left to do is to call isReachable()
method from the APIRequest
class:
API helper is equipped to handle network connectivity! If you want to test this, you can write something like this in the LoginScreen
file:
Of course, it’s better to create a ViewModifier
to encapsulate these two lines of styling code that are duplicated here, but I’ll leave that to you 😉
If you followed everything we’ve done so far and then tried to login without internet connection, your login screen should look like this:
NOTE: When you test internet connectivity, do not use the simulator, as it behaves inconsistently, and you won’t be able to test it properly. Use an actual iOS device instead.
Network detection is done! Let’s add a few more handy features to our APIRequest
class and wrap it up.
As our project gets bigger, we might encounter use cases where the API doesn’t take any parameters or doesn’t produce any response. Our API helper class must be able to handle these scenarios. Also, we need support for query items that might be required in API calls (usually GET
request parameters). Finally, we need to distinguish between authorized and non-authorized calls so we can add our Bearer token as a header in all authorized requests.
Here’s how we can easily extend our APIRequest
to support all these functionalities (as usual, added lines of code are marked in the comments):
That’s it! We’ve got a fully functional APIRequest
helper class that we can use for all sorts of requests! If we want to support more features in the future, we can extend this class, but our API helper is now more than capable of handling all our needs. Now, when we want to implement a new action, we can make a new instance of APIRequest
and provide the necessary parameters and completion handlers.
No duplicate code! Scalability all the way 😉
Demo project ❤️️
If you want to download a project that contains everything we’ve done so far, you can do it by clicking here.
“Build your first SwiftUI app” is part of a series of articles designed to help you get started with iOS app Development.
If you have any questions on any of the above-outlined thoughts, feel free to share them in the comment section.
Click here to read Part 1.: Project setup
Click here to read Part 2.: Project Architecture
Click here to read Part 3.: Create the Login screen
Click here to read Part 3.: Set up a mock server with Postman
Click here to read Part 5.: Handling authorization
Next part ⏭️
We’ve created a solid blueprint for our SwiftUI apps! However, we still don’t know how to send our apps to the AppStore so the world can enjoy our magnificent work. In the next article, we will learn what is needed to upload our app to the AppStore and how to do it. Exciting times are ahead! 🤩