RxRetroSwift
它有什么功能?
它简化了您的 RESTful API 调用,自动将 HttpResponse
转换为指定的模型,以及使用苹果公司新的 Codable 功能处理错误。
例如,在一个获取特定用户信息的请求中,您有一个 User
模型,您只需使 User 模型符合 Codable,并在使用 RequestCaller 时指定它。
{
"name":"kel",
"email":"[email protected]"
}
符合 Codable 的 User 模型。
struct User: Codable {
var name:String
var email:String
}
这将会自动将响应转换为 User 实例模型。
示例
let caller = RequestCaller(config: URLSessionConfiguration.default)
func fetchUser(byUserId userId) -> Observable<Result<User, ErrorModel>> {
let request:URLRequest = RequestModel(
httpMethod: .get,
path: "v1/users/\(userId)")
.asURLRequest()
return caller.call(request)
}
假设它是一个用户数组的示例;由于 Array 符合 Codable,您只需指定类型为 [User]
。
示例
func fetchUsers() -> Observable<Result<[User], ErrorModel>> {
let request:URLRequest = RequestModel(
httpMethod: .get,
path: "v1/users")
.asURLRequest()
return caller.call(request)
}
关于处理响应错误
RxRetroSwift 提供了一个 typealias ErrorCodable,它是 HasErrorInfo 和 Decodable 协议的组合
public typealias DecodableError = Decodable & HasErrorInfo
例如,您的登录请求的 JSON 错误响应是
{
"message": "Unable to login."
"details": {
"password": "You changed your password 2 months ago."
}
}
并且您的模型是
struct ErrorModel {
var errorCode:Int?
var message:String
var details:[String:String]
}
如何处理不期望返回对象或模型的请求?
RxRetroSwift 提供了一个方法,它将返回 Observable
public func call<DecodableErrorModel:DecodableError>(_ request: URLRequest)
-> Observable<Result<RawResponse, DecodableErrorModel>>
public struct RawResponse {
public var statusCode:Int
public var data:Data?
init(statusCode:Int, data:Data?) {
self.statusCode = statusCode
self.data = data
}
}
示例
要运行示例项目,请先克隆仓库,然后从 Example 目录运行 pod install
。
需求
功能
- 易于使用且简单,只需几行代码(不包括 RxSwift)。
- 干净整洁的实现。
- 灵活的错误处理。
- 简化您的REST API客户端。
待办事项
- 单元测试和集成测试(完成)
- 添加示例(完成)
- 支持您
URLRequest
的不同身份验证方法。
安装
CocoaPods
RxRetroSwift 现可通过 CocoaPods 获取。要安装它,只需将以下行添加到您的 Podfile 中
pod 'RxRetroSwift'
Swift 包管理器
.package(url: "https://github.com/michaelhenry/RxRetroSwift", from: "2.1"),
示例实现
使用JSONPlaceholder API。您还可以查看示例项目
class APIClient {
static var shared = APIClient()
var caller = RequestCaller.shared
private init() {
RequestModel.defaults.baseUrl = "https://jsonplaceholder.typicode.com"
}
func fetchPosts() -> Observable<Result<[Post], ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "posts")
.asURLRequest()
return caller.call(request)
}
func insertPost(post:Post) -> Observable<Result<Post, ErrorModel>> {
let request = RequestModel(
httpMethod: .post,
path: "posts",
payload: post.dictionaryValue)
.asURLRequest()
return caller.call(request)
}
func fetchComments() -> Observable<Result<[Comment], ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "comments")
.asURLRequest()
return caller.call(request)
}
func fetchAlbums() -> Observable<Result<[Album], ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "albums")
.asURLRequest()
return caller.call(request)
}
func fetchPhotos() -> Observable<Result<[Photo], ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "photos")
.asURLRequest()
return caller.call(request)
}
func fetchTodos() -> Observable<Result<[Todo], ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "todos")
.asURLRequest()
return caller.call(request)
}
func fetchUsers() -> Observable<Result<[User],ErrorModel>> {
let request = RequestModel(
httpMethod: .get,
path: "users")
.asURLRequest()
return caller.call(request)
}
}
测试
class TestAPIClient:QuickSpec {
override func spec() {
describe("Using JSONPlaceholder API") {
let apiClient = APIClient.shared
it("Check Posts result count"){
let observable = apiClient.fetchPosts()
expect(observable.map { $0.value!.count }).first == 100
}
it("Can insert post"){
var post = Post()
let title = "This is my post"
let userId = 101
let body = "This is a message body"
post.title = title
post.userId = userId
post.body = body
let observable = apiClient.insertPost(post: post)
expect(observable.map { $0.value?.title ?? "" }).first == title
expect(observable.map { $0.value?.userId ?? 0 }).first == userId
expect(observable.map { $0.value?.body ?? "" }).first == body
}
it("Check Comments result count"){
let observable = apiClient.fetchComments()
expect(observable.map { $0.value!.count }).first == 500
}
it("Check Albums result count"){
let observable = apiClient.fetchAlbums()
expect(observable.map { $0.value!.count }).first == 100
}
it("Check Photos result count"){
let observable = apiClient.fetchPhotos()
expect(observable.map { $0.value!.count }).first == 5000
}
it("Check Todos result count"){
let observable = apiClient.fetchTodos()
expect(observable.map { $0.value!.count }).first == 200
}
it("Check Users result count"){
let observable = apiClient.fetchUsers()
expect(observable.map { $0.value!.count }).first == 10
}
}
}
}
贡献
请随意提交拉取请求或提出任何有用的建议。
作者
Michael Henry Pantaleon, [email protected]
许可协议
RxRetroSwift 在MIT许可下可用。更多信息请查看LICENSE文件。