RFAPI
英文 简体中文
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。您可以通过更改定义管理器的 defaultRequestSerializer
和 defaultResponseSerializer
属性全局修改它。如果您需要调整特定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内置消息。
示例