Handle tons of API requests in Generical way, including JSON decode and Unit test in Swift
It’s very often seen a lot of different API request in a large project. If make each API unrelated, once there are needs to change some common characteristic, you will face a considerable pain to rewrite your code. However, things can be simpler when you were using generic. Because each API need to have related Codable Class/struct, therefore we need to have a Data struct remember all the detail of an API endpoint.
What an API endpoint have?
When it came to designing a system, it came to a question: What makes it look like itself? What is an API endpoint detail essential to us? Let’s try to list some characteristics of an API:
- API has URL
- API has an HTTP method
- API has query
- API has header
- API has body
- API response body has encoded type, such as String, JSON, XML, Protobuf
- API may response different base on the request’s info
- API may fail due to internet condition
Next, we can think what the share key feature of a unique API is? Then we conclude the rest are those who make an API unique.
- APIs have URL, which can be String
- APIs have HTTP method, which limits by RESTful API 4 cases, GET, POST, PUT, DELETE.
- APIs have optional keyValue pair query, which can be Dictionary.
- APIs have optional keyValue pair header, which can be Dictionary.
- APIs have a body, but it depends on the header, however, request taking Data as the body. Therefore the body can be Data.
- APIs response can be Any encoded. This part can not fit in a solid type.
- APIs usually response in two cases, either success or error, these can be limited
- APIs fail due to certain reason, which can be URLError
Here we have a list of share / unique list of API. Next, we can start to design our API request system.
We have a protocol
LikeAPIEndpoint, which did not follow AnyObject, it means that Struct and Enum can follow it. Second, we have three limited generic types in Codable and Error. Third, we have properties that limit some of those are read-only. Fourth, we have a function produce an Optional URLRequest, which take a baseURL that make it easy to switch domain, a setting manipulating URLRequest. Because the function
makeReques(baseURL:setting:) is identical in the case we have, we can make a default behavior for it.
And now we can construct an endpoint like this:
Fetch by a URLSession Engine
First, make the interface of URLSession Engine:
Second, handle the detail of the engine:
Using API engine
Test in Unit test
Because this article is not focusing on the Unit test, this part will just show the code.
After running test, you can watch the test result to scan through each API outcomes.
In the project, you can have each API endpoint save in a file because each will act differently. Sometimes it is not typical for change API result rapidly, but after reading this clear, now you can handle API like handling an object.
Make sure you did read it clearly. If you don’t, feel free to ask.