Last active
August 22, 2019 21:02
-
-
Save backslash-f/189bde80cc5d39ee14cbfc538f750b81 to your computer and use it in GitHub Desktop.
Network / APIClient / REST abstraction in a Swift Playground
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 | |
| import PlaygroundSupport | |
| /// Async. | |
| PlaygroundPage.current.needsIndefiniteExecution = true | |
| /// | |
| /// Movie Model Codable | |
| /// | |
| struct MovieModel: Codable { | |
| let title: String | |
| let country: String | |
| let released: String | |
| private enum CodingKeys: String, CodingKey { | |
| case title = "Title" | |
| case country = "Country" | |
| case released = "Released" | |
| } | |
| } | |
| /// | |
| /// API Request Abstraction | |
| /// | |
| public enum RequestType: String { | |
| case GET, POST | |
| } | |
| protocol APIRequest { | |
| var method: RequestType { get } | |
| var path: String { get } | |
| var parameters: [String : String] { get } | |
| } | |
| extension APIRequest { | |
| func request(with baseURL: URL) -> URLRequest { | |
| guard var components = URLComponents(url: baseURL.appendingPathComponent(path), resolvingAgainstBaseURL: false) else { | |
| fatalError("Unable to create URL components") | |
| } | |
| components.queryItems = parameters.map { | |
| URLQueryItem(name: String($0), value: String($1)) | |
| } | |
| guard let url = components.url else { | |
| fatalError("Could not get url") | |
| } | |
| var request = URLRequest(url: url) | |
| request.httpMethod = method.rawValue | |
| request.addValue("application/json", forHTTPHeaderField: "Accept") | |
| return request | |
| } | |
| } | |
| /// | |
| /// Movie Request | |
| /// | |
| class MovieRequest: APIRequest { | |
| var method = RequestType.GET | |
| var path = "" | |
| var parameters = [String: String]() | |
| init(title: String) { | |
| parameters["t"] = title | |
| parameters["apiKey"] = "YOUR_OMDB_API_KEY" | |
| } | |
| } | |
| /// | |
| /// API Client | |
| /// | |
| enum APIError: Error { | |
| case SomeError | |
| } | |
| class APIClient { | |
| private let baseURL = URL(string: "http://www.omdbapi.com/")! | |
| func send<T: Codable>(_ apiRequest: APIRequest, completion: @escaping (Result<T, APIError>) -> Void) { | |
| let request = apiRequest.request(with: self.baseURL) | |
| let task = URLSession.shared.dataTask(with: request) { (data, response, error) in | |
| guard error == nil else { | |
| completion(.failure(.SomeError)) | |
| return | |
| } | |
| guard let data = data else { | |
| completion(.failure(.SomeError)) | |
| return | |
| } | |
| do { | |
| let model: T = try JSONDecoder().decode(T.self, from: data) | |
| completion(.success(model)) | |
| } catch { | |
| print(error) | |
| completion(.failure(.SomeError)) | |
| } | |
| } | |
| task.resume() | |
| } | |
| } | |
| /// | |
| /// Usage | |
| /// | |
| let movieRequest = MovieRequest(title: "taxi+driver") | |
| APIClient().send(movieRequest) { (result: Result<MovieModel, APIError>) -> Void in | |
| switch result { | |
| case .success(let movie): | |
| print(movie.title) | |
| print(movie.country) | |
| print(movie.released) | |
| case .failure(let error): | |
| print(error) | |
| } | |
| } | |
| /// | |
| /// Output | |
| /// | |
| /* | |
| Taxi Driver | |
| USA | |
| 08 Feb 1976 | |
| */ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment