Swift: Connect with API using Async Await
The sample code below shows the non-reactive ways to connect with an API endpoint using async-await. The code is a generic implementation for API connection. This means it can be used with any model class as long as the model class implements the Decodable protocol. This means it can be directly used in any network layer implementation.
The below code can be found here. The code below would be mostly self-explanatory, please refer to the comments for more clarity.
/*Enum to capture various errors during the connection.*/
enum NetworkError: Error
case badUrl
case decodingError
case badRequest
case noData
case custom(Error)
}
2. Create the Protocol with Generic Model for the Network Service Class.
领英推荐
/*Create the Protocol, With Generic T which is a Decodable */
protocol NetworkServiceProtocol {
func fetchDataFromApi <T:Decodable>(withUrl: String) async -> Result <T,NetworkError>
}
3. Implement the Network Service Class for Generic Model.
class NetworkService: NetworkServiceProtocol {
?? ?
func fetchDataFromApi<T>(withUrl: String) async -> Result<T, NetworkError> where T : Decodable {
? ? ? ? guard let url = URL(string: withUrl) else {
? ? ? ? ? ? return .failure(.badUrl)
? ? ? ? }
? ? ? do {
? ? ? ? let (data, response) = try await URLSession.shared.data(from: url)
? ? ? ? ? ? if ((response as? HTTPURLResponse)?.statusCode != 200) {
? ? ? ? ? ? ? ? return .failure(.badRequest)
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? let response = try JSONDecoder().decode(T.self, from: data)
? ? ? ? ? ? ? ? return .success(response)
? ? ? ? ? ? }
? ? ? ? } catch let error {
? ? ? ? ? ? debugPrint(error)
? ? ? ? }
? ? ? ? return .failure(.decodingError)
? ? }
}
4. Invoke the Service. Please notice WebCharacterResponse which is my model object as it captures the JSON data specific to the API which I am using. You can use your own response object as is, the only condition being your response object should also implement the decodable protocol.
?
func fetchData(forPage: Int) async {
? ? ? ? let urlString = AppUrls.baseUrl + "\(forPage)"
? ? ? ? let result: Result<WebCharactersResponse, NetworkError> =
await networkService.fetchDataFromApi(withUrl: urlString)
? ? ? ? switch result {
? ? ? ? case .success( let characterResponse):
? ? ? ? ? ? if let characters = characterResponse.results {
? ? ? ? ? ? ? ? self.characters.append(contentsOf: characters) ?
? ? ? ? ? ? }
? ? ? ? case .failure(let error):
? ? ? ? ? ? print(error)
? ? ? ? }
? ? }