TRON 是一个轻量级的网络抽象层,构建于 Alamofire 之上。 它可以被用来极大地简化与 RESTful JSON Web 服务的交互。
Codable
协议。我们设计 TRON 的目标是简单易用,并且非常容易定制。 完成初始设置后,使用 TRON 非常直接。
let request: APIRequest<User,APIError> = tron.codable.request("me")
request.perform(withSuccess: { user in
print("Received User: \(user)")
}, failure: { error in
print("User request failed, parsed error: \(error)")
})
TRON 框架包含 Codable 实现。 要使用 SwiftyJSON,请 import TRONSwiftyJSON
框架。 要使用 RxSwift 包装器,请 import RxTRON
。
pod 'TRON', '~> 5.3.0'
仅核心子规范,没有 SwiftyJSON 依赖
pod 'TRON/Core', '~> 5.3.0'
TRON 的 RxSwift 扩展
pod 'TRON/RxSwift', '~> 5.3.0'
TRON
由 MLSDev Inc. 积极开发中。 欢迎提交 Pull Request!
TRON
对象用作 APIRequest
的初始配置器,设置所有基本值并配置为与 baseURL 一起使用。
let tron = TRON(baseURL: "https://api.myapp.com/")
您需要保持对 TRON
对象的强引用,因为它持有 Alamofire.Manager,Alamofire.Manager 正在运行所有请求。
URLBuildable
协议用于将相对路径转换为 URL,该 URL 将被请求使用。
public protocol URLBuildable {
func url(forPath path: String) -> URL
}
默认情况下,TRON
使用 URLBuilder
类,该类只是将相对路径附加到基本 URL,这在大多数情况下都足够了。 您可以通过更改 TRON
上的 urlBuilder
属性来全局自定义 URL 构建过程,或者通过修改 APIRequest
上的 urlBuilder
属性来本地自定义单个请求。
要发送 APIRequest
,请在 APIRequest
上调用 perform(withSuccess:failure:)
方法
let alamofireRequest = request.perform(withSuccess: { result in }, failure: { error in})
或者,您可以使用 performCollectingTimeline(withCompletion:)
方法,该方法在完成闭包中包含 Alamofire.Response
request.performCollectingTimeline(withCompletion: { response in
print(response.timeline)
print(response.result)
})
在这两种情况下,如果需要,您都可以额外链接 Alamofire.Request
方法
request.perform(withSuccess: { result in }, failure: { error in }).progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
print(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
}
通用的 APIRequest
实现允许我们在甚至发送请求之前定义预期的响应类型。 在 Alamofire
DataResponseSerializerProtocol
之上,我们为错误处理添加了一个额外的协议。
public protocol DataResponseSerializerProtocol {
associatedtype SerializedObject
public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Self.SerializedObject
}
public protocol ErrorSerializable: Error {
init?(serializedObject: Any?, request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?)
}
使用 Swift4 Codable
协议解析模型很简单,实现 Codable
协议
struct User: Codable {
let name : String
let id: Int
}
然后发送请求
let request: APIRequest<User,APIError> = tron.codable.request("me")
request.perform(withSuccess: { user in
print("Received user: \(user.name) with id: \(user.id)")
})
可以自定义模型和错误解析的解码器
let userDecoder = JSONDecoder()
let request : APIRequest<User,APIError> = tron.codable(modelDecoder: userDecoder).request("me")
TRON
提供了 JSONDecodable
协议,允许我们使用 SwiftyJSON 解析模型
public protocol JSONDecodable {
init(json: JSON) throws
}
要使用 SwiftyJSON
解析来自服务器的响应,您所需要做的就是创建一个符合 JSONDecodable
类型的类型,例如
class User: JSONDecodable {
let name : String
let id: Int
required init(json: JSON) {
name = json["name"].stringValue
id = json["id"].intValue
}
}
然后发送请求
let request: APIRequest<User,MyAppError> = tron.swiftyJSON.request("me")
request.perform(withSuccess: { user in
print("Received user: \(user.name) with id: \(user.id)")
})
对于 Swift 内置类型(如 String、Int、Float、Double 和 Bool),也存在 JSONDecodable
协议的默认实现,因此您可以轻松地执行以下操作
let request : APIRequest<String,APIError> = tron.swiftyJSON.request("status")
request.perform(withSuccess: { status in
print("Server status: \(status)") //
})
在您不关心实际响应的情况下,您还可以使用 Alamofire.Empty
结构体。
一些关于响应序列化的概念,包括数组响应序列化器,在 容器类型解析文档 中进行了描述
可以自定义 JSONSerialization.ReadingOptions
,SwiftyJSON.JSON
对象在解析响应数据时会使用这些选项
let request : APIRequest<String, APIError> = tron.swiftyJSON(readingOptions: .allowFragments).request("status")
使用 Swift 并发发送请求是通过代理对象 RequestSender
(或下载请求的 DownloadRequestSender
)完成的。 简单用法示例
let request : APIRequest<User, APIError> = tron.codable.request("/me")
do {
let user = try await request.sender().value
// user variable contains User type
} catch {
// Network request failed
}
如果您更喜欢接收包含成功模型或错误模型的结果,您也可以这样做
let request : APIRequest<User, APIError> = tron.codable.request("/me")
let result = await request.sender().result
// result is Result<User,APIError>
如果需要,还有一个包含所有请求信息的 response
异步属性
let request : APIRequest<User, APIError> = tron.codable.request("/me")
let response = await request.sender().response
// response: AFDataResponse<Model>
对于上传请求,监控上传进度并将其显示给用户非常有用
let request : APIRequest<User, APIError> = tron.codable.request("/me/profile_picture")
.upload("/post", fromFileAt: urlForResource("cat", withExtension: "jpg"))
.method(.post)
let sender = request.sender()
Task {
for await progress in sender.uploadProgress {
// Update progress view, progress: Progress
}
}
let result = await sender.result
与上传请求类似,下载请求具有作为异步序列实现的 downloadProgress 属性
Task {
for await progress in sender.downloadProgress {
// Update download view, progress: Progress
}
}
如果您只关心下载的文件 URL,而不关心解析的数据模型,您可以等待请求发送器上的 responseURL 属性
let destination = Alamofire.DownloadRequest.suggestedDownloadDestination()
let request: DownloadAPIRequest<URL, APIError> = tron
.download("/download",
to: destination,
responseSerializer: FileURLPassthroughResponseSerializer())
do {
let fileURL = try await request.sender().responseURL
} catch {
// Handle error
}
let request : APIRequest<Foo, APIError> = tron.codable.request("foo")
_ = request.rxResult().subscribe(onNext: { result in
print(result)
})
let multipartRequest : UploadAPIRequest<Foo,APIError> = tron.codable.uploadMultipart("foo", formData: { _ in })
multipartRequest.rxResult().subscribe(onNext: { result in
print(result)
})
TRON
包含用于错误的内置解析。 APIError
是 ErrorSerializable
协议的实现,其中包括几个有用的属性,可以从不成功的请求中获取
request.perform(withSuccess: { response in }, failure: { error in
print(error.request) // Original URLRequest
print(error.response) // HTTPURLResponse
print(error.data) // Data of response
print(error.fileURL) // Downloaded file url, if this was a download request
print(error.error) // Error from Foundation Loading system
print(error.serializedObject) // Object that was serialized from network response
})
struct Users
{
static let tron = TRON(baseURL: "https://api.myapp.com")
static func create() -> APIRequest<User,APIError> {
tron.codable.request("users").post()
}
static func read(id: Int) -> APIRequest<User, APIError> {
tron.codable.request("users/\(id)")
}
static func update(id: Int, parameters: [String:Any]) -> APIRequest<User, APIError> {
tron.codable.request("users/\(id)").put().parameters(parameters)
}
static func delete(id: Int) -> APIRequest<User,APIError> {
tron.codable.request("users/\(id)").delete()
}
}
使用这些请求非常简单
Users.read(56).perform(withSuccess: { user in
print("received user id 56 with name: \(user.name)")
})
为您的 API 引入命名空间也很好
enum API {}
extension API {
enum Users {
// ...
}
}
这样您就可以像这样调用您的 API 方法
API.Users.delete(56).perform(withSuccess: { user in
print("user \(user) deleted")
})
模拟功能内置于 APIRequest
本身。 您需要模拟成功的请求所需要做的就是设置 apiStub 属性并启用 stubbingEnabled
API.Users.get(56)
.stub(with: APIStub(data: User.fixture().asData))
.perform(withSuccess: { stubbedUser in
print("received stubbed User model: \(stubbedUser)")
})
可以在 TRON
对象上全局启用模拟,也可以在单个 APIRequest
上本地启用模拟。 模拟不成功的请求也很容易
API.Users.get(56)
.stub(with: APIStub(error: CustomError()))
.perform(withSuccess: { _ in },
failure: { error in
print("received stubbed api error")
})
您还可以选择延迟模拟时间
request.apiStub.stubDelay = 1.5
let request = tron.codable.upload("photo", fromFileAt: fileUrl)
let request = tron.codable.upload("photo", data: data)
let request = tron.codable.upload("photo", fromStream: stream)
let request: UploadAPIRequest<EmptyResponse,MyAppError> = tron.codable.uploadMultipart("form") { formData in
formData.append(data, withName: "cat", mimeType: "image/jpeg")
}
request.perform(withSuccess: { result in
print("form sent successfully")
})
let responseSerializer = TRONDownloadResponseSerializer { _,_, url,_ in url }
let request: DownloadAPIRequest<URL?, APIError> = tron.download("file",
to: destination,
responseSerializer: responseSerializer)
TRON
包含插件系统,允许对大多数请求事件做出反应。
插件可以在 TRON
实例本身上全局使用,也可以在具体的 APIRequest
上本地使用。 请记住,添加到 TRON
实例的插件将为每个请求调用。 全局和本地插件有一些非常酷的用例。
默认情况下,不使用任何插件,但是作为 TRON
框架的一部分实现了两个插件。
NetworkActivityPlugin
用于监视请求并控制 iPhone 状态栏中的网络活动指示器。 此插件假定您的应用程序中只有一个 TRON
实例。
let tron = TRON(baseURL: "https://api.myapp.com", plugins: [NetworkActivityPlugin()])
NetworkLoggerPlugin
用于以可读格式将响应记录到控制台。 默认情况下,它仅打印失败的请求,跳过成功的请求。
本地插件有一些非常酷的概念,其中一些在专门的 PluginConcepts 页面中进行了描述。
我们致力于构建尽可能最好的工具来与 RESTful Web 服务进行交互。 但是,我们理解每个工具都有其用途,因此,了解可以使用哪些其他工具来实现相同的目标始终是有用的。
TRON
受到 Moya framework 和 LevelUPSDK 的极大启发,后者已不再开源。
TRON
在 MIT 许可证下发布。 有关详细信息,请参阅 LICENSE。
TRON
由 MLSDev, Inc. 维护。 我们专注于提供移动和 Web 开发中的一体化解决方案。 我们的团队遵循精益原则并根据敏捷方法工作,以交付最佳结果,从而减少开发预算及其时间表。