Last active
October 10, 2023 13:39
-
-
Save staticVoidMan/b6049546f68994c8daf241495b100d52 to your computer and use it in GitHub Desktop.
A scalable easy-to-use Network Manager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Example based on API service: `https://api.quotable.io` | |
| */ | |
| import Foundation | |
| //MARK: Usage Example | |
| let provider: QuoteProvider = QuoteAPIProvider() | |
| Task { | |
| do { | |
| let result = try await provider.getRandomQuote() | |
| print(result) | |
| } catch { | |
| print(error) | |
| } | |
| } | |
| Task { | |
| do { | |
| let result = try await provider.getQuote(withId: "zUEhc50DjK7") | |
| print(result) | |
| } catch { | |
| print(error) | |
| } | |
| } | |
| //MARK: NetworkManager component | |
| enum NetworkManagerError: Error { | |
| case invalidURL(string: String) | |
| } | |
| enum HTTPMethod: String { | |
| case get = "GET" | |
| case post = "POST" | |
| } | |
| protocol Requestable { | |
| var base: String { get } | |
| var route: String { get } | |
| var httpMethod: HTTPMethod { get } | |
| } | |
| extension Requestable { | |
| func buildRequest() throws -> URLRequest { | |
| let urlString = base + route | |
| guard let url = URL(string: urlString) | |
| else { throw NetworkManagerError.invalidURL(string: urlString) } | |
| var request = URLRequest(url: url) | |
| request.httpMethod = httpMethod.rawValue | |
| return request | |
| } | |
| } | |
| final class RequestManager { | |
| func send<T: Decodable>(_ request: Requestable) async throws -> T { | |
| let request = try request.buildRequest() | |
| let (data, _) = try await URLSession.shared.data(for: request) | |
| let result = try JSONDecoder().decode(T.self, from: data) | |
| return result | |
| } | |
| } | |
| //MARK: Model | |
| struct Quote: Decodable { | |
| let id: String | |
| let author: String | |
| let content: String | |
| enum CodingKeys: String, CodingKey { | |
| case id = "_id" | |
| case author | |
| case content | |
| } | |
| } | |
| //MARK: API | |
| enum APIEndpoints { | |
| case base | |
| case randomQuote | |
| case quote(id: String) | |
| } | |
| extension APIEndpoints { | |
| var path: String { | |
| switch self { | |
| case .base: | |
| "https://api.quotable.io/" | |
| case .randomQuote: | |
| "random" | |
| case let .quote(id): | |
| "quotes/\(id)" | |
| } | |
| } | |
| } | |
| //MARK: Provider | |
| protocol QuoteProvider { | |
| func getRandomQuote() async throws -> Quote | |
| func getQuote(withId id: String) async throws -> Quote | |
| } | |
| // MARK: Request Builder | |
| extension Requestable { | |
| var base: String { APIEndpoints.base.path } | |
| } | |
| struct RandomQuoteRequest: Requestable { | |
| var route: String { APIEndpoints.randomQuote.path } | |
| var httpMethod: HTTPMethod { .get } | |
| } | |
| struct QuoteRequest: Requestable { | |
| let id: String | |
| var route: String { APIEndpoints.quote(id: id).path } | |
| var httpMethod: HTTPMethod { .get } | |
| } | |
| final class QuoteAPIProvider: QuoteProvider { | |
| lazy var manager = RequestManager() | |
| func getRandomQuote() async throws -> Quote { | |
| let request = RandomQuoteRequest() | |
| return try await manager.send(request) | |
| } | |
| func getQuote(withId id: String) async throws -> Quote { | |
| let request = QuoteRequest(id: id) | |
| return try await manager.send(request) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment