Fetch

Coverage Status Circle CI

Swift 中的简单 HTTP。隐藏了样板代码。Fetch 允许您发出基于协议的 HTTP 请求,同时提供一个自定义的类或结构体,能够将响应解析为您的应用程序可以理解的模型对象。 使所有内容都可以轻松进行单元测试,而无需借助存根网络连接或使用异步测试。

Request(请求)

这是一个用于描述请求的协议。 为您希望发出的任何请求创建此协议的实现。 例如,如果您想获取用户记录,您可以创建一个如下的请求:

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)"
    ]
  }
}

Parsable(可解析)

这是一个用于处理响应的协议。 它有一个单一的函数,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))
  }
}

RequestPerforming(请求执行者)

此协议描述了一个能够实际发出请求的对象。 它有一个单一的函数:

  @discardableResult
  func perform<T: Parsable>(_ request: Request, completion: @escaping (Result<T>) -> Void) -> Cancellable

它应该接收一个请求,开始执行它,并返回对正在执行的操作的可取消引用。 Fetch 中有一个此协议的实现,Session,它包装了 URLSession 以进行简单的数据请求。 您可以为 Session 提供您自己的 URLSessionOperationQueue 来进行回调,但默认情况下它使用 URLSession.sharedOperationQueue.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  
      }
    }
  }
}

Example(示例)

该项目中有一个示例应用程序,向您展示如何实现 Parsable。 在生产代码中,我显然建议使用您最喜欢的 swift JSON 解析库。

Using in your own project(在您自己的项目中使用)

使用此库的最简单方法是通过 Carthage。 只需添加

github "dhardiman/Fetch"

到您的 Cartfile。

在本地构建和运行测试时,请确保使用以下命令初始化 Carthage 依赖项:

carthage bootstrap --platform iOS

License(许可)

MIT