它简化了你的 RESTful API 调用,使用苹果最新的 Codable 功能自动将 HttpResponse
转换为指定的 Model 以及 Error。
例如,在请求获取特定用户信息并且你有一个 User
模型时,你所要做的就是让 User 模型遵循 Codable 协议,并在使用 RequestCaller 时指定它。
{
"name":"kel",
"email":"me@iamkel.net"
}
User
模型遵循 Codable 协议。
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)
}
关于处理 ResponseError
RxRetroSwift 提供了一个类型别名 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<Result<RawResponse>, DecodableErrorModel>>。
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
}
}
要运行示例项目,请克隆 repo,然后首先从 Example 目录运行 pod install
。
URLRequest
的不同身份验证方法。RxRetroSwift 现在可以通过 CocoaPods 获得。 要安装它,只需将以下行添加到您的 Podfile 中
pod 'RxRetroSwift'
.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
}
}
}
}
欢迎随意提交 pull request 或提出任何有用的建议。
Michael Henry Pantaleon, me@iamkel.net
RxRetroSwift 在 MIT 许可下可用。 有关更多信息,请参见 LICENSE 文件。