Last active
September 2, 2019 17:35
-
-
Save MaximBazarov/d683096e57cb67a27bfe188e1746329c to your computer and use it in GitHub Desktop.
Trying to make a Networking layer more clean
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
/// USAGE /// | |
// Declarative endpoint description | |
// MARK: - Endpoints | |
struct LoginRequest: Request { | |
let endpoint = "api/v3/auth" | |
let method = HTTPMethod.get | |
let headers: [String : String] = [:] | |
// Body params | |
let email: String | |
let password: String | |
// Result | |
typealias ResultType = Session; struct Session: Decodable { | |
let token: String | |
} | |
// Builder for body | |
var body: [String : String] { | |
return [ | |
"email": email, | |
"password": password | |
] | |
} | |
} | |
// MARK: - API Service | |
class APIService { | |
/// Auth Function | |
/// - Parameter email: | |
/// - Parameter password: | |
/// - Parameter transport: Optional parameter, default transport is shared url session | |
private static func auth( | |
email: String, | |
password: String, | |
transport: Transport<LoginRequest> = URLSession.shared.transport(for: LoginRequest.self) | |
) -> Promise<Response<LoginRequest.Session>> { | |
return transport.perform ( | |
LoginRequest(email: email, password: password) | |
) | |
} | |
} | |
/// IMPLEMENTATION /// | |
import Foundation | |
import PromiseU | |
// MARK: - Transport<T> | |
struct Transport<T: Request> { | |
let decode: (Data) -> Result<T.ResultType, Error> = jsonDecoder | |
let encode: (T.Body) -> Result<Data, Error> = jsonEncoder | |
let perform: (T) -> Promise<Response<T.ResultType>> | |
// MARK: - Default implementations | |
static func jsonDecoder(data: Data) -> Result<T.ResultType, Error> { | |
do { | |
return .success( | |
try JSONDecoder().decode(T.ResultType.self, from: data) | |
) | |
} catch { | |
return .failure(error) | |
} | |
} | |
static func jsonEncoder(body: T.Body) -> Result<Data, Error> { | |
do { | |
return .success( | |
try JSONEncoder().encode(body) | |
) | |
} catch { | |
return .failure(error) | |
} | |
} | |
} | |
enum HTTPMethod { | |
case get, post, put, delete, update | |
} | |
protocol Request { | |
associatedtype Body: Encodable | |
associatedtype ResultType: Decodable | |
var body: Body { get } | |
var endpoint: String { get } | |
var method: HTTPMethod { get } | |
var headers: [String: String] { get } | |
} | |
protocol ResponseType { | |
associatedtype ResultType: Decodable | |
} | |
enum Response<T: Decodable>: ResponseType { | |
typealias ResultType = T | |
case test | |
case networkError(Error) | |
case non200(URLResponse) | |
case success(T) | |
} | |
// MARK: - URLSession based transport | |
extension URLSession { | |
func transport<T: Request>(for endpoint: T.Type) -> Transport<T> { | |
return Transport<T> { endpoint in | |
return Promise(.test) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment