Last active
July 10, 2019 02:05
-
-
Save yoxisem544/f2a42087637f8d630b93bef8765281a9 to your computer and use it in GitHub Desktop.
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 Moya | |
import RxSwift | |
import PromiseKit | |
import Alamofire | |
import SwiftyJSON | |
typealias Method = HTTPMethod | |
extension String { | |
var urlEscaped: String { | |
return addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! | |
} | |
} | |
// 定義一個 protocol 需要預先指定 response 的 type | |
protocol DecodableResponse { | |
associatedtype ResponseType: Decodable | |
var jsonDecodingEntryPath: String? { get } | |
} | |
extension DecodableResponse { | |
// default to no json entry point | |
var jsonDecodingEntryPath: String? { return nil } | |
} | |
final public class API { | |
public static let shared = API() | |
private init() {} | |
fileprivate static let provider = MoyaProvider<MultiTarget>() | |
} | |
// MARK: - Promise Extension | |
extension API { | |
func request<Request: TargetType & DecodableResponse>(_ request: Request, atKeyPath path: String? = nil, failsOnEmptyData: Bool = true) -> Promise<Request.ResponseType> { | |
let target = MultiTarget.init(request) | |
return Promise { seal in | |
API.provider.request(target, completion: { response in | |
switch response { | |
case .success(let r): | |
do { | |
if let path = path { | |
let result = try r.map(Request.ResponseType.self, atKeyPath: path, using: JSONDecoder(), failsOnEmptyData: failsOnEmptyData) | |
seal.fulfill(result) | |
} else { | |
let result = try JSONDecoder().decode(Request.ResponseType.self, from: r.data) | |
seal.fulfill(result) | |
} | |
} catch let e { | |
seal.reject(e) | |
} | |
case .failure(let e): | |
seal.reject(e) | |
} | |
}) | |
} | |
} | |
// MARK: - Promise | |
func request<Request: TargetType & DecodableResponse>(_ request: Request) -> Promise<Request.ResponseType> { | |
return API.shared.request(request, atKeyPath: request.jsonDecodingEntryPath, failsOnEmptyData: true) | |
} | |
func request<Request: TargetType>(_ request: Request, failsOnEmptyData: Bool = false) -> Promise<JSON?> { | |
let target = MultiTarget.init(request) | |
return Promise { seal in | |
API.provider.request(target, completion: { response in | |
switch response { | |
case .success(let r): | |
do { | |
seal.fulfill(try JSON(data: r.data)) | |
} catch let e { | |
seal.reject(e) | |
} | |
case .failure(let e): | |
seal.reject(e) | |
} | |
}) | |
} | |
} | |
} | |
// MARK: - Rx extension | |
extension API: ReactiveCompatible {} | |
extension Reactive where Base == API { | |
// 每當我傳入一個 request 時,我都會檢查他的 response 可不可以被 decode, | |
// conform DecodableResponseTargetType 的意義在此, | |
// 因為我們已經先定好 ResponseType 是什麼了, | |
// 儘管 request 不知道確定是什麼型態,但一定可以被 JSONDecoder 解析。 | |
func request<Request: TargetType & DecodableResponse>(_ request: Request) -> Single<Request.ResponseType> { | |
let target = MultiTarget.init(request) | |
return API.provider.rx.request(target) | |
.filterSuccessfulStatusCodes() | |
.map(Request.ResponseType.self) // 在此會解析 Response,具體怎麼解析,交由 data model 的 decodable 去處理。 | |
} | |
func request<Request: TargetType>(_ request: Request, failsOnEmptyData: Bool = false) -> Single<Any> { | |
let target = MultiTarget.init(request) | |
return API.provider.rx.request(target) | |
.filterSuccessfulStatusCodes() | |
.mapJSON(failsOnEmptyData: failsOnEmptyData) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment