Last active
September 15, 2019 12:53
-
-
Save SwiftyAlex/2a195af55fa903b5d533f22d9ca324f6 to your computer and use it in GitHub Desktop.
A Simple, TypeSafe routing protocol built around Combine.
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
public protocol Route { | |
/// Request & ResponseType are forced, but `EmptyRequest` allows you to skip encoding/decoding | |
associatedtype RequestType: Encodable | |
associatedtype ResponseType: Decodable | |
static var method: HTTPMethod { get } | |
static var path: String { get } | |
/// Optional instance of `RequestType` that gets encoded if present | |
var requestObject: RequestType? { get set } | |
/// Any query parameters. | |
var queryParemeters: [URLQueryItem] { get set } | |
/// This function has a generic implenetation for the more simple routes, all others should have their own. | |
func toRequest() -> URLRequest | |
} | |
extension Route { | |
/// The basic implementation of `Route` `toRequest` adds parameters and builds the path. | |
public func toRequest() -> URLRequest { | |
// Add all the parameters | |
var urlComponents = URLComponents(string: "https://jsonplaceholder.typicode.com/" + Self.path)! | |
urlComponents.queryItems = queryParemeters | |
var request = URLRequest(url: urlComponents.url!) | |
// If we're using a route that has to send data, lets encode it here. | |
// In the case any special mapping needs to be done, this method should be overriden. | |
if let requestObject = requestObject, !(requestObject is EmptyRequest) { | |
request.httpBody = try? JSONEncoder().encode(requestObject) | |
} | |
return request | |
} | |
} | |
/// A Router using `Combine` | |
public static func performRequest<R: Route>(_ route: R, data: R.RequestType) -> AnyPublisher<R.ResponseType, Error> { | |
return URLSession.shared.dataTaskPublisher(for: route.toRequest()) | |
.map(\.data) | |
.mapError { NetworkError(from: $0) } | |
.decode(type: R.ResponseType.self, decoder: JSONDecoder()) | |
.mapError { _ in NetworkError.decodingFailed } | |
.eraseToAnyPublisher() | |
} | |
// Return a publisher and then do a thing | |
public static func performRequest<R: Route>(_ route: R) -> AnyPublisher<URLResponse, Error> where R.ResponseType == EmptyRequest { | |
return URLSession.shared.dataTaskPublisher(for: route.toRequest()) | |
.map(\.response) | |
.mapError { NetworkError(from: $0) } | |
.eraseToAnyPublisher() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment