From aaf8706300c5aaf765784f2f03be18632ef1b95b Mon Sep 17 00:00:00 2001 From: Victor Bodinaud Date: Mon, 3 Jun 2024 13:46:51 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Remove=20unused=20default=20headers?= =?UTF-8?q?=20&=20allow=20request=20specific=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/Hermes/Hermes.swift | 106 +++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/Sources/Hermes/Hermes.swift b/Sources/Hermes/Hermes.swift index 2f2832b..47957d0 100644 --- a/Sources/Hermes/Hermes.swift +++ b/Sources/Hermes/Hermes.swift @@ -14,6 +14,11 @@ public enum NetworkError: Error { case notFound } +public protocol HermesMiddleware { + func processRequest(_ request: inout URLRequest) + func processResponse(_ data: Data?, _ response: URLResponse?, error: Error?) +} + extension NetworkError: LocalizedError { public var errorDescription: String? { switch self { @@ -58,18 +63,21 @@ public struct Resource { let url: URL var method: HTTPMethod = .get([]) var modelType: T.Type + var headers: [String: String] - public init(url: URL, method: HTTPMethod, modelType: T.Type) { + public init(url: URL, method: HTTPMethod, modelType: T.Type, headers: [String: String] = [:]) { self.url = url self.method = method self.modelType = modelType + self.headers = headers } } public final class Hermes { public static let shared = Hermes() private var config: HermesConfiguration - + private var middlewares: [HermesMiddleware] = [] + private init(config: HermesConfiguration = HermesConfiguration()) { self.config = config } @@ -77,63 +85,87 @@ public final class Hermes { public func configure(_ config: HermesConfiguration) { self.config = config } - + + public func addMiddleware(_ middleware: HermesMiddleware) { + middlewares.append(middleware) + } + private var defaultHeaders: [String: String] { - var headers = ["Content-Type": "application/json"] - if let token = UserDefaults.standard.string(forKey: "authToken") { - headers["Authorization"] = "Bearer \(token)" - } - headers.merge(config.defaultHeaders) { (_, new) in new } + var headers = [ + "Content-Type": "application/json", + "Accept": "application/json" + ] + + headers.merge(config.defaultHeaders) { _, new in new } + return headers } public func load(_ resource: Resource) async throws -> T { - var request = URLRequest(url: resource.url) request.httpMethod = resource.method.name - + + for middleware in middlewares { + middleware.processRequest(&request) + } + switch resource.method { - case .get(let queryItems): - if let queryItems = queryItems { - var components = URLComponents(url: resource.url, resolvingAgainstBaseURL: false) - components?.queryItems = queryItems - request.url = components?.url - } - case .post(let data), - .put(let data), - .patch(let data): - request.httpBody = data - case .delete: - break + case .get(let queryItems): + if let queryItems = queryItems { + var components = URLComponents(url: resource.url, resolvingAgainstBaseURL: false) + components?.queryItems = queryItems + request.url = components?.url + } + case .post(let data), + .put(let data), + .patch(let data): + request.httpBody = data + case .delete: + break } - request.allHTTPHeaderFields = defaultHeaders + var headers = defaultHeaders - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = defaultHeaders - let session = URLSession(configuration: configuration) - - let (data, response) = try await session.data(for: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw NetworkError.invalidResponse + if !resource.headers.isEmpty { + headers.merge(resource.headers) { _, new in new } } - try validate(response: httpResponse) + request.allHTTPHeaderFields = headers - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = config.decodingStrategy + let session = URLSession(configuration: URLSessionConfiguration.default) do { - return try decoder.decode(resource.modelType, from: data) + let (data, response) = try await session.data(for: request) + + for middleware in middlewares { + middleware.processResponse(data, response, error: nil) + } + + guard let httpResponse = response as? HTTPURLResponse else { + throw NetworkError.invalidResponse + } + + try validate(response: httpResponse) + + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = config.decodingStrategy + + do { + return try decoder.decode(resource.modelType, from: data) + } catch { + throw NetworkError.decodingError + } } catch { - throw NetworkError.decodingError + for middleware in middlewares { + middleware.processResponse(nil, nil, error: error) + } + throw error } } private func validate(response: HTTPURLResponse) throws { switch response.statusCode { - case 200...299: + case 200 ... 299: return case 400: throw NetworkError.badRequest -- 2.49.1