Skip to content

Instantly share code, notes, and snippets.

@MaximBazarov
Last active September 2, 2019 17:35
Show Gist options
  • Save MaximBazarov/d683096e57cb67a27bfe188e1746329c to your computer and use it in GitHub Desktop.
Save MaximBazarov/d683096e57cb67a27bfe188e1746329c to your computer and use it in GitHub Desktop.
Trying to make a Networking layer more clean
/// 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