KiNetworking
[](https://travis-ci.org/Anh Phan Tran/KiNetworking)
这个库是一个为高配置 + TDD 构建的现代网络层。库利用 Alamofire、Promises 和 SwiftyJSON 的特性,帮助您直接从 API 调用到模型转换。
示例
要运行示例项目,克隆仓库,然后首先从 Example 目录中运行 pod install
。
需求
安装
通过 CocoaPods 可以获取 KiNetworking。安装它,只需将以下行添加到您的 Podfile 文件中
pod 'KiNetworking'
用法
要发出请求,首先需要提供请求运行的 API 服务。这样,您可以为应用在的每个环境获取一个服务实例。
API 服务需要 APIServiceConfiguration 来初始化
let config = APIServiceConfig(
name: "Staging",
base: "https://stagingBaseURL",
commonHeaders: [
"Someheaderkey": "SomeValue"
])
config?.debugEnabled = .request // .none, .request, .response
let service = APIService.init(config!)
获取服务后,您可以创建一个请求并在服务上执行,如下所示
let request = Request(method: .get, endpoint: "someEndpoint")
request.execute(on: service).then(...).catch(...)
服务将调用请求(请求协议)并返回响应(响应协议)。
请求和请求协议
请求协议有以下参数
public protocol RequestProtocol {
// Endpoint of the request
var endpoint: String { get }
// Request's params that will be encoded into the final request URL
var parameters: Parameters? { get }
// Request specific headers, will override service's header if share the same key, else, append to the service's headers
var additionalHeaders: HeadersDict? { get set }
// Method: .get, .post, .put, .patch, .delete
var method: Alamofire.HTTPMethod { get }
// Request specific cache policy, if nil will use the service's cache policy
var cachePolicy: URLRequest.CachePolicy? { get }
// Request specific timeout, if nil will use the service's timeout interval
var timeout: TimeInterval? { get }
// Queue that we make the request, if nil will use the service's context
var context: DispatchQueue? { get }
// Body of the request: .json, .formURL, .custom, .data
var body: RequestBody? { get set }
func headers(in service: APIServiceProtocol) -> HeadersDict
func fullURL(in service: APIServiceProtocol) throws -> URL
func urlRequest(in service: APIServiceProtocol) throws -> URLRequest
}
实现了这个协议的名为 Request 的基类
响应和响应协议
响应协议有以下参数
public protocol ResponseProtocol {
/// Type of response (success or failure)
var result: Response.Result { get }
/// Encapsulates the metrics for a session task.
/// It contains the taskInterval and redirectCount, as well as metrics for each request / response
/// transaction made during the execution of the task.
var metrics: ResponseTimeline? { get }
/// Request
var request: RequestProtocol { get }
/// Return the http url response
var httpResponse: HTTPURLResponse? { get }
/// Return HTTP status code of the response
var httpStatusCode: Int? { get }
/// Return the raw Data instance response of the request
var data: Data? { get }
/// Attempt to decode Data received from server and return a JSON object.
/// If it fails it will return an empty JSON object.
/// Value is stored internally so subsequent calls return cached value.
///
/// - Returns: JSON
func toJSON() -> JSON
/// Attempt to decode Data received from server and return a String object.
/// If it fails it return `nil`.
/// Call is not cached but evaluated at each call.
/// If no encoding is specified, `utf8` is used instead.
///
/// - Parameter encoding: encoding of the data
/// - Returns: String or `nil` if failed
func toString(_ encoding: String.Encoding?) -> String?
}
实现了这个协议的名为 Response 的基类
操作
这个库原始就提供了 DataOperation 和 JSONOperation。
DataOperation 只是直接返回用于您操作的数据响应的操作。
另一方面,DecodableOperation 或 JSONOperation 可以帮助您直接从请求中返回模型。
// Customer class with Decodable
struct Customer: Decodable {
}
class GetCustomerRecord: DecodableOperation<Customer> {
public init(customerId: Int) {
super.init()
self.request = SampleJWTRequest(method: .get, endpoint: "/users/\(customerId)", parameters: nil, encoder: JSONEncoding.default)
self.request.timeout = 15
}
}
// Customer class with JSON
class Customer {
init?(from json: JSON) {
// Do your init here
}
}
class GetCustomerRecord: JSONOperation<Customer> {
public init(customerId: Int) {
super.init()
self.request = SampleJWTRequest(method: .get, endpoint: "/users/\(customerId)", parameters: nil, encoder: JSONEncoding.default)
self.request.timeout = 15
self.onParseResponse = { json in
return Customer(from: json)
}
}
}
// When you need to invoke the get customer record API:
...
let service = APIService(...)
GetCustomerRecord(customerId: 123).execute(on: service).then { customer in
// Do what you want with customer
}.catch { error in
// Show error
}
APIServiceDelegate
每个API服务可以选择一个代理,如果需要的话
public protocol APIServiceDelegate: class {
func service(_ apiService: APIServiceProtocol, willExecute request: RequestProtocol)
func service(_ apiService: APIServiceProtocol, shouldHandleCode errorCode: Int, on request: RequestProtocol) -> Bool
func service(_ apiService: APIServiceProtocol, handleResponse: ResponseProtocol, on request: RequestProtocol) -> Promise<ResponseProtocol>
}
此代理可以用以授权或刷新请求的访问令牌。
Author
Anh Phan Tran, [email protected]
License
KitNetworking 适用于MIT许可证。有关更多信息,请参阅LICENSE文件。