RFAPI 2.1.1

RFAPI 2.1.1

BB9z 维护。



RFAPI 2.1.1

  • BB9z

RFAPI

Build Status Codecov CocoaPods

英文 简体中文 🇨🇳

RFAPI 是一个专门针对 API 请求而设计的网络请求库。它是基于 AFNetworking 的 URL 会话包装器。

特性

  • 它通过规则创建请求并处理响应,而不是在代码中拼接 URL。不再需要手动解码模型并添加额外的错误处理逻辑。
  • 请求过程可以绑定到加载进度和 UI 控制状态。
  • 美观的请求方法,比链式调用更易读,易于扩展。
  • 通过特定的分组标识符获取和取消请求。您可以在不同的代码上下文中不传递请求对象来控制请求。
  • 自动模型解码支持不同的库。
  • 多个请求完成回调,方便在各种使用场景中,集中式错误处理,自动错误处理。

缺点

RFAPI 的最大问题是它过于陈旧。2014 年,v1 版本的设计和 95% 的实现工作已经完成。在那之后,许多年只是做了很少的微小改变。虽然良好的设计不会过时,但相关的技术栈已经更新。如果您仍然使用 NSOperation 来管理请求,如果没有 URL 会话,没有 Swift,没有 Codable,那么它并不算过时。

我在2019年底开始将其升级到v2版本。主要目标是支持AFNetworking v3。前提是在尽可能的情况下保持与旧版本的兼容性。已实现新的接口设计。Swift中的用户体验已经得到改进。这并不意味着可以完全进行改造。

  • 用于重载的主要类的接口在Swift中使用起来很困难。它们是为Objective-C设计的。当转移到Swift时,Objective-C的灵活设计变得很奇怪。
  • 不支持Codable,支持Swift的私有特性很麻烦。
  • 当前URL会话功能尚未得到充分利用。目前仅实现了数据任务。尚未支持下载和上传任务。
  • 下载功能有限。如果您需要下载器,请检查其他库。

未来,Alamofire的封装将开放另一个项目。此库不会用Swift重写。

使用说明

CocoaPods 安装

由于依赖因素,仅支持通过CocoaPods进行集成。没有对SPM和Carthage的支持计划。

pod 'RFAPI'

指定开发分支以安装最新版本

pod 'RFAPI',
    :git => 'https://github.com/RFUI/RFAPI.git',
    :branch => 'develop'

定义一个API

与大多数网络库不同,你不能使用URL对象进行请求。相反,RFAPI使用API定义对象来描述不仅如何请求,还如何处理响应。

let define = RFAPIDefine()
define.name = RFAPIName(rawValue: "TopicListRecommended")
define.path = "https://example.com/api/v2/topics/recommended"
define.method = "GET"
define.needsAuthorization = true
define.responseExpectType = .objects
define.responseClass = "TopicEntity"

一般应创建一个默认定义。之后,在创建其他定义时,只需提供默认定义的不同部分。设置默认规则的示例

let api = ... // RFAPI instance
let defaultDefine = RFAPIDefine()
defaultDefine.baseURL = URL(string: "https://example.com/")
defaultDefine.pathPrefix = "api/v2/"
defaultDefine.method = "GET"
defaultDefine.needsAuthorization = true
api.defineManager.defaultDefine = defaultDefine

使用默认定义,上述API定义可以简化为

let define = RFAPIDefine()
define.name = RFAPIName(rawValue: "TopicListRecommended")
define.path = "topics/recommended"
define.responseExpectType = .objects
define.responseClass = "TopicEntity"

更推荐的方法是从配置文件中加载定义。你可以从本地文件(如json、plist)加载定义,甚至从服务器获取配置。例如

{
  "DEFAULT": {
    "Base": "https://example.com/",
    "Path Prefix": "api/v2/",
    "Method": "GET",
    "Authorization": true
  },
  "TopicListRecommended": {
    "Path": "topics/recommended",
    "Response Type": 3,
    "Response Class": "TopicEntity"
  },
  "UserLogin": {
    "Method": "POST",
    "Path": "user/login",
    "Authorization": false,
    "Response Type": 2,
    "Response Class": "LoginResponseEntity"
  },
  ...
}

文件配置应为类型 [String: [String: Any]] 的字典,键是API名称,DEFAULT 是默认定义。使用配置文件,可以将其加载到定义管理器中,然后可以直接使用API名称进行请求。例如

let rules = ... // Configuration loaded
let api = ...   // RFAPI instance
defineManager.setDefinesWithRulesInfo(rules)

默认情况下,请求和响应的内容格式都是JSON。您可以通过更改定义管理器的 defaultRequestSerializerdefaultResponseSerializer 属性全局修改它。如果您需要调整特定API,您可以在API定义中指定序列化器类型。例如

{
  "FormUpload": {
    "Method": "POST",
    "Path": "common/formupload",
    "Serializer": "AFHTTPRequestSerializer",
    "Response Serializer": "AFPropertyListResponseSerializer",
    "Response Type": 1
  }
}

其他配置文件示例:[Demo项目配置](https://github.com/RFUI/RFAPI/blob/develop/Example/iOS-Swift/TestAPIDefine.plist),[iOS 项目模板/APIDefine.plist](https://github.com/BB9z/iOS-Project-Template/blob/master/App/Networking/APIDefine.plist)

发送请求

您可以直接在发送请求时传递定义对象;如果定义已存在于定义管理器中,您可以直接传递API名称。通过上下文对象传递所有其他参数。

let api = ... // RFAPI instance
api.request(name: "TopicListRecommended") { c in
    c.parameters = ["page": 1, "page_size": 20]
    c.loadMessage = "List Loading"
    c.success { _, rsp in
        guard let topics = rsp as? [TopicEntity] else { fatalError() }
        ...
    }
}

更多用法,请查看Cookbook

与通用方法的区别

  • 取消操作不被视为失败

    当请求被取消时,不会调用失败回调。也不会用NSURLErrorCancelled错误参数调用失败回调。

    但是您可以从RFAPITask对象在完成或完成回调中获取到NSURLErrorCancelled错误。

  • 大多数参数可修改

    除了与定义相关的属性外,通过上下文传递的大部分参数都不会被复制。您可以自由地传递可修改的数组、字典、字符串或其他内容,并在请求发送后更改这些值。RFAPI允许这样做,并认为您知道自己在做什么。

本地化

您可以通过将可本地化的字符串放入主包的默认表中来本地化RFAPI内置消息。

示例