Skip to content

Instantly share code, notes, and snippets.

@yoxisem544
Last active July 10, 2019 02:05
Show Gist options
  • Save yoxisem544/f2a42087637f8d630b93bef8765281a9 to your computer and use it in GitHub Desktop.
Save yoxisem544/f2a42087637f8d630b93bef8765281a9 to your computer and use it in GitHub Desktop.
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