Last active
October 12, 2017 23:02
-
-
Save fellipecaetano/1c0450976528c852bdff00dbc67dd703 to your computer and use it in GitHub Desktop.
At attempt at solving networking. Just paste it inside an Xcode Playground and start from there.
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
import Foundation | |
struct HTTPRequest<T> { | |
let method: HTTPMethod | |
let path: String | |
let parameters: [String: Any] | |
let headers: [String: String] | |
let response: ExpectedHTTPResponse<T> | |
} | |
extension HTTPRequest: Authenticatable { | |
typealias Key = Authentication | |
func authenticated(with key: Authentication) -> HTTPRequest<T> { | |
return HTTPRequest( | |
method: .get, | |
path: path, | |
parameters: [ | |
"token": key.token | |
].merging(parameters, uniquingKeysWith: { lhs, _ in lhs }), | |
headers: headers, | |
response: response | |
) | |
} | |
} | |
struct ExpectedHTTPResponse<T> { | |
let decoded: (Data) throws -> T | |
} | |
enum HTTPMethod { | |
case get | |
case post | |
} | |
/* Authenticated */ | |
struct Authenticated<T: Authenticatable, K>: Authenticatable where T.Key == K { | |
typealias Key = K | |
private let key: K? | |
private let value: T | |
private init (key: K?, value: T) { | |
self.key = key | |
self.value = value | |
} | |
static func of(_ value: T) -> Authenticated<T, K> { | |
return Authenticated(key: nil, value: value) | |
} | |
func authenticated(with key: K) -> Authenticated<T, K> { | |
return Authenticated(key: key, value: value) | |
} | |
func map<V>(_ fn: (T) throws -> V) rethrows -> Authenticated<V, K> { | |
return Authenticated<V, K>(key: key, value: try fn(value)) | |
} | |
func flatMap<V>(_ fn: (T) throws -> Authenticated<V, K>) rethrows -> Authenticated<V, K> { | |
return try map(fn).dematerialized() | |
} | |
func dematerialized() -> T { | |
return key.map(value.authenticated(with:)) ?? value | |
} | |
} | |
protocol Authenticatable { | |
associatedtype Key | |
func authenticated(with key: Key) -> Self | |
} | |
/* Endpoint */ | |
struct Endpoint<B, T> { | |
private let baseURL: B | |
private let value: T | |
init (baseURL: B, value: T) { | |
self.baseURL = baseURL | |
self.value = value | |
} | |
func map<V>(_ fn: (T) throws -> V) rethrows -> Endpoint<B, V> { | |
return Endpoint<B, V>(baseURL: baseURL, value: try fn(value)) | |
} | |
func flatMap<V>(_ fn: (T) throws -> Endpoint<B, V>) rethrows -> Endpoint<B, V> { | |
let args = try map(fn).dematerialized().value.dematerialized() | |
return Endpoint<B, V>(baseURL: args.baseURL, value: args.value) | |
} | |
func dematerialized() -> (baseURL: B, value: T) { | |
return (baseURL, value) | |
} | |
} | |
/* Request creators */ | |
typealias LegacyAPIRequest<T> = Endpoint<LegacyAPIURL, HTTPRequest<T>> | |
typealias AuthenticatedLegacyAPIRequest<T> = Endpoint<LegacyAPIURL, Authenticated<HTTPRequest<T>, Authentication>> | |
typealias SearchAPIRequest<T> = Endpoint<SearchAPIURL, HTTPRequest<T>> | |
typealias AuthenticatedSearchAPIRequest<T> = Endpoint<SearchAPIURL, Authenticated<HTTPRequest<T>, Authentication>> | |
func create<T>(request: HTTPRequest<T>) -> LegacyAPIRequest<T> { | |
return .of(request) | |
} | |
func create<T>(request: HTTPRequest<T>) -> AuthenticatedLegacyAPIRequest<T> { | |
return .of(.of(request)) | |
} | |
func create<T>(request: HTTPRequest<T>) -> SearchAPIRequest<T> { | |
return .of(request) | |
} | |
func create<T>(request: HTTPRequest<T>) -> AuthenticatedSearchAPIRequest<T> { | |
return .of(.of(request)) | |
} | |
extension Endpoint where B == LegacyAPIURL { | |
static func of(_ value: T) -> Endpoint<B, T> { | |
return Endpoint(baseURL: LegacyAPIURL(), value: value) | |
} | |
} | |
extension Endpoint where B == SearchAPIURL { | |
static func of(_ value: T) -> Endpoint<B, T> { | |
return Endpoint(baseURL: SearchAPIURL(), value: value) | |
} | |
} | |
extension Authenticated where K == Authentication { | |
static func of(_ value: T) -> Authenticated<T, K> { | |
let key = Environment.current.authentication | |
return Authenticated(key: key, value: value) | |
} | |
} | |
/* Request definition */ | |
func EventsByCategoryRequest(category: Category) -> AuthenticatedLegacyAPIRequest<[Event]> { | |
return create( | |
request: HTTPRequest( | |
method: .get, | |
path: "/events/category", | |
parameters: ["category": category], | |
headers: ["X-App-Token": "8asd8urjahdfue"], | |
response: APIEventsResponse() | |
) | |
) | |
} | |
func APIEventsResponse() -> ExpectedHTTPResponse<[Event]> { | |
return ExpectedHTTPResponse { _ in | |
throw APIEventsError() | |
} | |
} | |
/* Models */ | |
struct Authentication { | |
let token = "" | |
} | |
struct LegacyAPIURL { | |
var url: URL { | |
return URL(string: "https://legacy.api.com")! | |
} | |
} | |
struct SearchAPIURL { | |
var url: URL { | |
return URL(string: "https://search.api.com")! | |
} | |
} | |
struct Category {} | |
struct Event {} | |
struct APIEventsError: Error {} | |
/* App */ | |
struct Environment { | |
static let current = Environment() | |
let authentication = Authentication() | |
} | |
print(EventsByCategoryRequest(category: Category())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment