Skip to content

Instantly share code, notes, and snippets.

@hlung
Last active February 21, 2022 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hlung/b292467c1488e5cbf121131f54c25dee to your computer and use it in GitHub Desktop.
Save hlung/b292467c1488e5cbf121131f54c25dee to your computer and use it in GitHub Desktop.
APIClient startDecodableRequest
import Foundation
class APIClient {
// 1 - Error enum
enum APIClientError: Error {
case dataTaskFailed(Error)
case noHTTPURLResponse
case badHTTPStatusCode(HTTPURLResponse)
case noData
case decodingFailed(Error)
case unknown(Error)
}
let session = URLSession.shared
func startDecodableRequest<T: Decodable>(
_ request: URLRequest,
decoder: JSONDecoder = JSONDecoder(),
completionQueue: DispatchQueue = DispatchQueue.main,
completion: @escaping ((Result<T, APIClientError>) -> Void)
) {
let task = session.dataTask(with: request,
completionHandler: { data, response, error in
do {
// 2 - Check error and status code
if let error = error {
throw APIClientError.dataTaskFailed(error)
}
guard let urlResponse = response as? HTTPURLResponse else {
throw APIClientError.noHTTPURLResponse
}
let validStatusCodes = 200...399
guard validStatusCodes.contains(urlResponse.statusCode) else {
throw APIClientError.badHTTPStatusCode(urlResponse)
}
// 3 - Decode data
guard let data = data else {
throw APIClientError.noData
}
let decoded: T
do {
decoded = try decoder.decode(T.self, from: data)
}
catch {
throw APIClientError.decodingFailed(error)
}
// 4 - Call completion for success
completionQueue.async {
completion(.success(decoded))
}
}
catch {
// 5 - Call completion for failure
let finalError = error as? APIClientError ?? .unknown(error)
completionQueue.async {
completion(.failure(finalError))
}
}
})
task.resume()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment