NamadaEatr 1.0.0

NamadaEatr 1.0.0

nayanda1 维护。



  • nayanda

NamadaEatr

NamadaEatr 是适用于 iOS 平台的 HTTP 请求助手。它是之前库 iOSEatr 的更新版、更好的版本,并且更加通用。

CI Status Version License Platform

示例

要运行示例项目,请先克隆仓库,然后在 Example 目录中首先运行 pod install

需求

安装

NamadaEatr 可通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中

pod 'NamadaEatr'

作者

nayanda, [email protected]

许可

NamadaEatr遵循MIT许可。有关更多信息,请参阅LICENSE文件。

使用示例

基本使用

NamadaEatr旨在简化HTTP请求的过程。您只需创建Eatr / HTTPRequestManager类请求即可。

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    .prepareDataRequest()
    .then { result in
    // do something with result
}

创建请求

要创建请求,可以这样做

Eatr.default.httpRequest(.get, withUrl: "https://myurl.com")
    .set(urlParameters: ["param1": "value1", "param2": "value2"])
    .set(headers: ["Authorization": myToken])
    .set(body: dataBody)
    ..
    ..

或者使用定制的 URLSession

// create session
var session = URLSession()
session.configuration = myCustomConfig
session.delegateQueue = myOperationQueue
..
..

// create Eatr instance
let eatr = Eatr(with: session)

// create request
eatr.httpRequest(.get, withUrl: "https://myurl.com")
    .set(urlParameters: ["param1": "value1", "param2": "value2"])
    .set(headers: ["Authorization": myToken])
    .set(body: dataBody)
    ..
    ..

最好保存Eatr实例并重复使用,因为它将仅使用相同的 URLSession 创建请求,除非您想为其他请求使用其他 URLSession

可用的HTTP方法枚举包括

  • post
  • get
  • put
  • patch
  • delete
  • head
  • connect
  • options
  • trace
  • none 如果您不想包含HTTP方法头
  • custom(String)

要设置自定义正文类型,您需要传递实现 HTTPBodyEncoder 对象的自定义类型编码器,以将对象编码进数据

Eatr.default.httpRequest(.get, withUrl: "https://myurl.com")
    .set(body: myObject, with encoder: myEndoder) -> Self
    ..
    ..

HTTPBodyEncoder 的声明是

public protocol HTTPBodyEncoder {
    var relatedHeaders: [String: String]? { get }
    func encoder(_ any: Any) throws -> Data
}

相关的headers是与这个编码相关联的头部,它将自动分配给请求头部。由于默认实现返回nil,这些方法都是可选的。

使用NamadaEatr默认body编码器设置body有一些不同的默认方法,分别是:

  • func set(body: Data) -> Self
  • func set(stringBody: String, encoding: String.Encoding = .utf8) -> Self
  • func set(jsonBody: [String: Any]) -> Self
  • func set(arrayJsonBody: [Any]) -> Self
  • func set(jsonEncodable: EObject) -> Self
  • func set(arrayJsonEncodable: [EObject]) -> Self

请求准备就绪后,再准备请求,这将返回Thenable

Eatr.default.httpRequest(.get, withUrl: "https://myurl.com")
    .set(urlParameters: ["param1": "value1", "param2": "value2"])
    .set(headers: ["Authorization": myToken])
    .set(body: dataBody)
    ..
    ..
    .prepareDataRequest()

或者对于下载,你需要提供目标位置URL,你需要将下载的数据保存到该位置

Eatr.default.httpRequest(.get, withUrl: "https://myurl.com")
    .set(urlParameters: ["param1": "value1", "param2": "value2"])
    .set(headers: ["Authorization": myToken])
    .set(body: dataBody)
    ..
    ..
    .prepareDownloadRequest(targetSavedUrl: myTargetUrl)

或者对于上传,你需要提供文件位置URL,你需要上传到该位置

Eatr.default.httpRequest(.get, withUrl: "https://myurl.com")
    .set(urlParameters: ["param1": "value1", "param2": "value2"])
    .set(headers: ["Authorization": myToken])
    .set(body: dataBody)
    ..
    ..
    .prepareUploadRequest(withFileLocation: myTargetUrl)

数据请求Thenable

创建数据请求后,你可以直接使用then方法执行请求

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .then { result in
    // do something with result
}

或者使用单独的完成

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .then(run: { result in
        // do something when get response
    }, whenFailed: { result in
        // do something when failed
    }
)

使用自定义调度程序,这将是指定完成运行的线程

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .completionDispatch(on: .global(qos: .background))
    .then(run: { result in
        // do something when get response
    }, whenFailed: { result in
        // do something when failed
    }
)

默认调度程序是DispatchQueue.main

或者甚至不使用完成

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .executeAndForget()

结果是URLResult对象,它包含

  • urlResponse: URLResponse?,这是原始响应,你可以在这里阅读文档这里
  • error: Error?,这是发生错误时的情况。在成功响应中将是nil
  • responseData: Data?,这是响应体的原始数据
  • isFailed: Bool,请求失败时为true
  • isSucceed: Bool,请求成功时为true
  • httpMessage: HTTPResultMessage?,这是请求的响应消息。如果结果不是HTTP结果,将为nil

HTTPResultMessage是来自URLResult的详细HTTP响应

  • url: HTTPURLCompatible,这是响应的原始URL
  • headers: Header,这是响应的头部
  • body: Data?,这是响应的内容
  • statusCode: Int,这是响应的状态码

你可以获取thenable对象或忽略它。它将返回包含请求状态的HTTPRequest

let request = Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .executeAndForget()
let status = request.status

状态包括:

  • running(Float),包含请求进度的百分比,从0 - 1
  • dropped
  • idle
  • completed(HTTPURLResponse),包含完成的响应
  • error(Error),如果有错误发生,将包含错误

你可以使用drop()函数取消请求

request.drop()

上传请求Thenable

上传请求基本上与数据请求在thenable方面相同。

下载请求Thenable

下载请求与数据请求或上传请求略有不同。下载请求可以被暂停和恢复,结果也不同

结果是包含以下内容的 DownloadResult 对象

  • urlResponse: URLResponse?,这是原始响应,你可以在这里阅读文档这里
  • error: Error?,这是发生错误时的情况。在成功响应中将是nil
  • dataLocalURL: URL? 表示下载数据的存放位置
  • isFailed: Bool,请求失败时为true
  • isSucceed: Bool,请求成功时为true

您可以暂停下载和恢复下载

request.pause()

let status = request.resume()

恢复下载将返回 ResumeStatus 枚举

  • 已恢复
  • 恢复失败

对数据请求解码响应体

要解析体,可以这样做

let decodedBody = try? result.message.parseBody(using: myDecoder)

parseBody 方法接受任何实现了 ResponseDecoder 协议的对象。ResponseDecoder 协议的声明如下

public protocol ResponseDecoder {
    associatedtype Decoded
    func decode(from data: Data) throws -> Decoded
}

因此,您可以这样做

class MyResponseDecoder: ResponseDecoder {
    typealias Decoded = MyObject
    
    func decode(from data: Data) throws -> MyObject {
        // do something to decode data into MyObject
    }
}

如果不希望从 Data 解析,可以使用默认的基本解码器

class MyJSONResponseDecoder: BaseJSONDecoder<MyObject> {
    typealias Decoded = MyObject
    
    override func decode(from json: [String: Any]) throws -> MyObject {
        // do something to decode json into MyObject
    }
}

class MyStringResponseDecoder: BaseStringDecoder<MyObject> {
    typealias Decoded = MyObject
    
    override func decode(from string: String) throws -> MyObject {
        // do something to decode string into MyObject
    }
}

HTTPResultMessage 包含默认的函数,可以自动解析体

  • func parseBody(toStringEndcoded encoding: String.Encoding = .utf8) throws -> String
  • func parseJSONBody() throws -> [String: Any]
  • func parseArrayJSONBody() throws -> [Any]
  • func parseJSONBody<DObject: Decodable>() throws -> DObject
  • func parseArrayJSONBody<DObject: Decodable>() throws -> [DObject]
  • func parseJSONBody<DOBject: Decodable>(forType type: DOBject.Type) throws -> DOBject
  • func parseArrayJSONBody<DObject: Decodable>(forType type: DObject.Type) throws -> [DObject]

验证器

您可以为响应添加验证,如下所示

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .validate(statusCodes: 0..<300)
    .validate(shouldHaveHeaders: ["Content-Type": "application/json"])
    .then(run: { result in
        // do something when get response
    }, whenFailed: { result in
        // do something when failed
    }
)

如果响应无效,那么将会出错,或者错误传递给 whenFailed 闭包中的错误。

提供的验证方法有

  • validate(statusCode: Int) -> Self
  • validate(statusCodes: Range) -> Self
  • validate(shouldHaveHeaders headers: [String:String]) -> Self

您可以为 HTTP 响应添加自定义验证器。验证器的类型是 URLValidator

public protocol HTTPValidator {
    func validate(for response: URLResponse) -> ValidationResult
}

ValidationResult 是一个枚举,包含

  • 有效
  • 无效
  • invalidWithReason(String) 无效,并提供自定义原因,该原因将在 HTTPError 错误中描述

您可以像这样放置您自定义的 URLValidator

Eatr.default
    .httpRequest(.get, withUrl: "https://myurl.com")
    ..
    ..
    .prepareDataRequest()
    .validate(using: MyCustomValidator())
    .then(run: { result in
        // do something when get response
    }, whenFailed: { result in
        // do something when failed
    }
)

如果您只想验证 HTTPURLResponse 并自动使其他内容无效,则可以使用 HTTPValidator

public protocol HTTPValidator: URLValidator {
    func validate(forHttp response: HTTPURLResponse) -> URLValidatorResult
}

记住你可以添加任意数量的验证器来验证响应,这些验证器将从第一个开始依次进行验证,直到响应结束或其中一个验证器返回无效。如果你没有提供任何URLValidator,则在服务器出错或无响应的情况下,它将视为无效,否则,所有响应都将视为有效。

聚合

你可以将两个或更多请求聚合到一个单例的 Promise 中,如下所示

request1.aggregate(with: request2)
    .aggregate(request3)
    .then { allResults in
    // do something with allResults
}

//or like this
RequestAggregator(aggregatedRequests)
    .then { allResults in
        // do something with allResults
}

结果是RequestAggregator.Result,它包含

  • results: [AggregatedResult],这是聚合请求的所有完成结果
  • isFailed: Bool,如果一个或多个请求失败,则该值为 true
  • areCompleted: Bool,如果所有请求都完成,则该值为 true

你也可以像获取单个请求一样获取请求,获取其状态或取消请求

let aggregatedRequests = request1.aggregate(with: request2)
    .aggregate(request3)
    .then { allResults in
    // do something with allResults
}
let aggregatedStatus = aggregatedRequests.status
aggregatedRequests.drop()

投稿

你知道如何,只需克隆并提交一个 pull request