Last active
October 31, 2017 09:19
-
-
Save wleii/36f31f9c49b444a5e65d1d4a7124ee1a to your computer and use it in GitHub Desktop.
Swift: a top-level design for network request, base Alamofire
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 Foundation | |
import Alamofire | |
enum HTTPResult<Value> { | |
case success(Value) | |
case failure(Error) | |
} | |
extension HTTPResult { | |
func map<T>(_ transform: ((Value) -> T)) -> HTTPResult<T> { | |
switch self { | |
case let .success(value): | |
return .success(transform(value)) | |
case let .failure(error): | |
return .failure(error) | |
} | |
} | |
func flatMap<T>(_ transform: ((Value) throws -> T)) -> HTTPResult<T> { | |
switch self { | |
case let .success(value): | |
do { | |
return try .success(transform(value)) | |
} catch { | |
return .failure(error) | |
} | |
case let .failure(error): | |
return .failure(error) | |
} | |
} | |
} | |
enum TransformError: Error, LocalizedError { | |
case notJsonType | |
var errorDescription: String? { | |
switch self { | |
case .notJsonType: | |
return "Not a JSON value Type" | |
} | |
} | |
} | |
struct Transform { | |
static func json(_ any: Any) throws -> [String: Any] { | |
if let dic = any as? [String: Any] { | |
return dic | |
}else { | |
throw TransformError.notJsonType | |
} | |
} | |
static func jsonArray(_ any: Any) throws -> [[String: Any]] { | |
if let dic = any as? [[String: Any]] { | |
return dic | |
}else { | |
throw TransformError.notJsonType | |
} | |
} | |
struct Model<T: Decodable> { | |
static func model(_ value: Data) throws -> T { | |
return try model(value) | |
} | |
static func model(_ value: Data) throws -> [T] { | |
return try model(value) | |
} | |
static func model(_ value: Data, using jsonDecoder: JSONDecoder = JSONDecoder()) throws -> T { | |
return try jsonDecoder.decode(T.self, from: value) | |
} | |
static func model(_ value: Data, using jsonDecoder: JSONDecoder = JSONDecoder()) throws -> [T] { | |
return try jsonDecoder.decode(T.self, from: value) as! [T] | |
} | |
static func model(_ value: [String: Any]) throws -> T { | |
return try model(value, using: JSONDecoder()) | |
} | |
static func model(_ value: [[String: Any]]) throws -> [T] { | |
return try model(value, using: JSONDecoder()) | |
} | |
static func model(_ value: [String: Any], using jsonDecoder: JSONDecoder = JSONDecoder()) throws -> T { | |
let data = try JSONSerialization.data(withJSONObject: value, options: JSONSerialization.WritingOptions.init(rawValue: 0)) | |
return try model(data) | |
} | |
static func model(_ value: [[String: Any]], using jsonDecoder: JSONDecoder = JSONDecoder()) throws -> [T] { | |
let dataList = try value.map( {try JSONSerialization.data(withJSONObject: $0, options: JSONSerialization.WritingOptions.init(rawValue: 0)) }) | |
return try dataList.map{ try jsonDecoder.decode(T.self, from: $0) } | |
} | |
} | |
} | |
public protocol NetworkRawResponse { } | |
extension DataResponse: NetworkRawResponse {} | |
extension DefaultDataResponse: NetworkRawResponse {} | |
extension DownloadResponse: NetworkRawResponse {} | |
extension DefaultDownloadResponse: NetworkRawResponse {} | |
open class Network { | |
public enum Method { | |
case get | |
case post | |
} | |
public enum Encoding { | |
case url | |
case json | |
case propertyList | |
case custom(ParameterEncoding) | |
} | |
private var url: URLConvertible? | |
private var method: Method = .get | |
private var parameters: Parameters = [:] | |
private var encoding: Encoding = .url | |
private var headers: HTTPHeaders = [:] | |
private var request: Request? | |
static func request(url: URL) -> Network { | |
let network = Network() | |
network.url = url | |
return network | |
} | |
private var rawResponse: ((NetworkRawResponse) -> Void)? | |
static func request(url: String) -> Network { | |
let network = Network() | |
network.url = url | |
return network | |
} | |
// TODO: Download | |
// TODO: Upload | |
func method(_ value: Method) -> Network { | |
method = value | |
return self | |
} | |
func parameters(_ value: [String: Any]) -> Network { | |
parameters = value | |
return self | |
} | |
func encoding(_ value: Encoding) -> Network { | |
encoding = value | |
return self | |
} | |
func headers(_ value: [String: String]) -> Network { | |
headers = value | |
return self | |
} | |
func rawResponse(_ response: @escaping (NetworkRawResponse) -> Void) -> Network { | |
rawResponse = response | |
return self | |
} | |
func response(_ completion: @escaping ((HTTPResult<Any>) -> Void)) -> Network { | |
// start request | |
guard let url = url else { | |
fatalError("please set request url") | |
} | |
let requestMethod: HTTPMethod | |
switch method { | |
case .get: | |
requestMethod = .get | |
case .post: | |
requestMethod = .post | |
} | |
let parameterEncoding: ParameterEncoding | |
switch encoding { | |
case .url: | |
parameterEncoding = URLEncoding.default | |
case .json: | |
parameterEncoding = JSONEncoding.default | |
case .propertyList: | |
parameterEncoding = PropertyListEncoding.default | |
case .custom(let encode): | |
parameterEncoding = encode | |
} | |
let dataRequest = Alamofire.request(url, method: requestMethod, parameters: parameters, encoding: parameterEncoding, headers: headers) | |
request = dataRequest | |
dataRequest | |
.responseJSON { (dataResponse) in | |
// this is call back rawReponse observer | |
self.rawResponse?(dataResponse) | |
switch dataResponse.result { | |
case let .success(value): | |
completion(.success(value)) | |
case let .failure(error): | |
// deal error | |
completion(.failure(error)) | |
} | |
} | |
return self | |
} | |
} | |
extension Network: CustomStringConvertible { | |
public var description: String { | |
return request?.description ?? "alamofire request haven't ready" | |
} | |
} | |
extension Network: CustomDebugStringConvertible { | |
public var debugDescription: String { | |
return request?.debugDescription ?? "alamofire request haven't ready" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment