enum HTTPMethod: String {
case post = "POST"
}
enum Errors: Error {
case invalidUrl
case invalidQuery
case invalidResponse
case httpStatus(Int)
}
protocol MyDecoder {
func decode<T: Decodable>(_: _ type: T.Type, from data: Data) throws -> T
}
final class NetworkService {
private let session: URLSession
private let encoder = JSONEncoder()
private let decoder: MyDecoder
init(
session: URLSession = .shared,
decoder: MyDecoder
) {
self.session = session
self.decoder = decoder
}
func request<Response: Decodable, Body: Encodable>(
urlString: String,
method: HTTPMethod,
body: Body? = nil,
headers: [String: String] = [:],
query: [String: String] = [:]
) async throws -> Response {
guard var components = URLComponents(string: urlString) else {
throw Errors.invalidUrl
}
if !query.isEmpty {
components.queryItems = query.map {
URLQueryItem(name: $0.key, value: $0.value)
}
}
guard let url = components.url else {
throw Errors.invalidQuery
}
var request = URLRequest(url: url)