Skip to content

Instantly share code, notes, and snippets.

@angelinaFri
Last active April 26, 2020 07:19
Show Gist options
  • Save angelinaFri/d44420be375a44ff28fb1ee9871da259 to your computer and use it in GitHub Desktop.
Save angelinaFri/d44420be375a44ff28fb1ee9871da259 to your computer and use it in GitHub Desktop.
Protocols & Generics
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