Last active
April 26, 2020 07:19
-
-
Save angelinaFri/d44420be375a44ff28fb1ee9871da259 to your computer and use it in GitHub Desktop.
Protocols & Generics
This file contains 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 UIKit | |
// Global variable | |
public var baseUrl = URL(string: "www.myApi.com")! | |
// Protocols | |
protocol Fetchable: Decodable { | |
static var apiBase: String { get } | |
} | |
protocol Transport { | |
func fetch(request: URLRequest, | |
completion: @escaping (Result<Data, Error>) -> Void) | |
} | |
//Wrapper class | |
class NetworkTransport: Transport { | |
static let shared = NetworkTransport() | |
let session: URLSession | |
init(session: URLSession = .shared) { | |
self.session = session | |
} | |
func fetch(request: URLRequest, completion: @escaping (Result<Data, Error>) -> Void) { | |
session.dataTask(with: request) { (data, _, error) in | |
if let error = error { completion(.failure(error))} | |
else if let data = data { completion(.success(data))} | |
}.resume() | |
} | |
} | |
// Models | |
struct User: Codable, Hashable { | |
let id: Int | |
let name: String | |
} | |
struct Document: Codable, Hashable { | |
let id: Int | |
let name: String | |
} | |
extension User: Fetchable { | |
static var apiBase: String { return "user" } | |
} | |
extension Document: Fetchable { | |
static var apiBase: String { return "document"} | |
} | |
func fetch<Model: Fetchable>(_ model: Model.Type, id: Int, completion: @escaping(Result<Model, Error>) -> Void) { | |
let urlRequest = URLRequest(url: baseUrl | |
.appendingPathComponent(Model.apiBase) | |
.appendingPathComponent("\(id)") | |
) | |
let session = URLSession.shared | |
session.dataTask(with: urlRequest) { | |
(data, _, error) in | |
if let error = error { | |
completion(.failure(error)) | |
} | |
else if let data = data { | |
let decoder = JSONDecoder() | |
completion(Result { | |
try decoder.decode(Model.self, from: data) | |
}) | |
} | |
}.resume() | |
} | |
// Client's only job is to be a concrete thing that holds a transport | |
struct Client { | |
let transport: Transport | |
init(transport: Transport) { self.transport = transport } | |
func fetchTransportWrapper<Model: Fetchable>(_ model: Model.Type, id: Int, completion: @escaping(Result<Model, Error>) -> Void) { | |
let urlRequest = URLRequest(url: baseUrl | |
.appendingPathComponent(Model.apiBase) | |
.appendingPathComponent("\(id)") | |
) | |
transport.fetch(request: urlRequest) { (data) in | |
completion(Result { | |
let decoder = JSONDecoder() | |
return try decoder.decode(Model.self, from: data.get()) | |
}) | |
} | |
} | |
} | |
struct AddHeaders: Transport { | |
let base: Transport | |
var headers: [String: String] | |
func fetch(request: URLRequest, | |
completion: @escaping (Result<Data, Error>) -> Void) { | |
var newRequest = request | |
for (key, value) in headers { | |
newRequest.addValue(value, forHTTPHeaderField: key) | |
} | |
base.fetch(request: newRequest, completion: completion) | |
} | |
} | |
let transport = AddHeaders(base: NetworkTransport.shared, headers: ["Authorization" : "..."]) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment