114 lines
2.9 KiB
Swift
Raw Normal View History

2022-12-04 17:21:11 +01:00
//
// APIClient.swift
// APIService
//
// Created by Javier Cicchelli on 04/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import Foundation
struct APIClient {
private let session: URLSession
private let decoder: JSONDecoder
private let makeURLRequest: MakeURLRequestUseCase
}
// MARK: - Initialisers
extension APIClient {
init(configuration: URLSessionConfiguration = .default) {
self.session = .init(configuration: configuration)
self.decoder = .init()
self.makeURLRequest = .init()
}
}
// MARK: - Client
extension APIClient: Client {
func request<Model>(
endpoint: some Endpoint,
model: Model.Type
) async throws -> Model where Model : Decodable {
let urlRequest = try makeURLRequest(endpoint: endpoint)
let (data, response) = try await session.data(for: urlRequest)
guard
let httpResponse = response as? HTTPURLResponse,
let responseStatus = ResponseStatus(rawValue: httpResponse.statusCode)
else {
throw APIClientError.responseNotReturned
}
switch responseStatus {
case .ok,
.created:
return try await decode(data, as: model)
case .noContent:
throw APIClientError.notSupported
case .badRequest:
throw APIClientError.itemAlreadyExist
case .notFound:
throw APIClientError.itemDoesNotExist
}
}
@discardableResult
func request(
endpoint: some Endpoint
) async throws -> Data {
let urlRequest = try makeURLRequest(endpoint: endpoint)
let (data, response) = try await session.data(for: urlRequest)
guard
let httpResponse = response as? HTTPURLResponse,
let responseStatus = ResponseStatus(rawValue: httpResponse.statusCode)
else {
throw APIClientError.responseNotReturned
}
switch responseStatus {
case .ok,
.noContent:
return data
case .created:
throw APIClientError.notSupported
case .badRequest:
throw APIClientError.itemIsNotFile
case .notFound:
throw APIClientError.itemDoesNotExist
}
}
}
// MARK: - Helpers
private extension APIClient {
func decode<Model: Decodable>(
_ data: Data,
as model: Model.Type
) async throws -> Model {
do {
decoder.dateDecodingStrategy = .formatted(.isoZulu)
return try decoder.decode(model, from: data)
} catch {
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(model, from: data)
}
}
}
// MARK: - Errors
public enum APIClientError: Error {
case responseNotReturned
case itemIsNotFile
case itemAlreadyExist
case itemDoesNotExist
case notSupported
}