Swift 中的简单 HTTP。隐藏了样板代码。Fetch 允许您发出基于协议的 HTTP 请求,同时提供一个自定义的类或结构体,能够将响应解析为您的应用程序可以理解的模型对象。 使所有内容都可以轻松进行单元测试,而无需借助存根网络连接或使用异步测试。
这是一个用于描述请求的协议。 为您希望发出的任何请求创建此协议的实现。 例如,如果您想获取用户记录,您可以创建一个如下的请求:
struct UserRequest: Request {
let url: URL
let method = HTTPMethod.get
let data: Data? = nil
let headers: [String: String]?
init(userId: Int, token: String) {
url = URL(string: "https://my-web-service.com/users/\(userId)")!
headers = [
"Authorization": "Bearer \(token)"
]
}
}
这是一个用于处理响应的协议。 它有一个单一的函数,static func parse(response: Response, errorParser: ErrorParsing?) -> Result<Self>
,旨在解释从请求收到的响应(包含数据、状态代码、原始请求和其他相关信息)。 实现此方法以确定成功或失败,并使用数据填充模型对象。 例如,如果解析来自上面用户请求的响应,您可以创建以下内容:
struct User {
let id: Int
let name: String
}
extension User: Parsable {
enum UserError: Error {
case statusCodeError
case parseError
}
static func parse(response: Response, errorParser: ErrorParsing?) -> Result<User> {
guard response.status == 200 else {
// Parse data for any error message
if let error = errorParser.parseError(from: response.data, status: response.status) {
return .failure(error)
}
return .failure(UserError.statusCodeError)
}
guard let data = response.data,
let parsedResponse = try? JSONSerialization.jsonObject(with: data, options: []) as? [[String: AnyObject]],
let id = parsedResponse["id"] as? Int,
let name = parsedResponse["name"] as? String else {
return .failure(UserError.parseError)
}
return .success(User(id: id, name: name))
}
}
此协议描述了一个能够实际发出请求的对象。 它有一个单一的函数:
@discardableResult
func perform<T: Parsable>(_ request: Request, completion: @escaping (Result<T>) -> Void) -> Cancellable
它应该接收一个请求,开始执行它,并返回对正在执行的操作的可取消引用。 Fetch 中有一个此协议的实现,Session
,它包装了 URLSession
以进行简单的数据请求。 您可以为 Session
提供您自己的 URLSession
和 OperationQueue
来进行回调,但默认情况下它使用 URLSession.shared
和 OperationQueue.main
。 如果您需要自定义行为,您也可以完全实现您自己的。 通过使用 RequestPerforming
,可以轻松地引入 mock 或 spy,以确保正在发出正确的请求。
如果发出用户请求,您可以执行以下操作:
protocol UserQueryable {
func findUser(id: Int)
}
class UserFetcher: UserQueryable {
let session: RequestPerforming
init(session: RequestPerforming = Session()) {
self.session = session
}
func findUser(id: Int) {
let request = UserRequest(id: id, token: token)
session.perform(request) { (result: Result<User>) in
switch result {
case .failure(let error):
print("\(error)")
case .success(let user):
// handle successful response
}
}
}
}
该项目中有一个示例应用程序,向您展示如何实现 Parsable
。 在生产代码中,我显然建议使用您最喜欢的 swift JSON 解析库。
使用此库的最简单方法是通过 Carthage。 只需添加
github "dhardiman/Fetch"
到您的 Cartfile。
在本地构建和运行测试时,请确保使用以下命令初始化 Carthage 依赖项:
carthage bootstrap --platform iOS