动机
在审查了许多 iOS REST 客户端后,我们发现它们都非常冗长,这是不必要的。这个库是从简化客户端与服务器之间通信的需求中产生的。
要求
- Swift 4+
对于 Swift 2.2、2.3 和 3,请查看分支。
文档
您可以在此 wiki 中阅读文档
用法
要将 EasyRest 添加到项目中,请在 Podfile 中添加以下内容
pod 'EasyRest'
pod 'EasyRest/PromiseKit'
模型示例
class Post : Codable {
var id: String?
var title: String?
}
路由示例
// Maps API calls and infos, like method and query params
enum JsonPlaceholderRoutable: Routable {
// Each API interaction is a case
case posts
// Using query params
case postsFilter(userId: Int)
// Example with path
case post(id: Int)
case deletePost(id: Int)
// Example with body
case makePost(body: PostModel)
// Example with path, body and header
case editPost(id: Int, body: PostModel)
case editTitle(id: Int, body: PostModel)
// Now test every possibility in a fashion Swift syntax
var rule: Rule {
switch(self) {
case .posts:
return Rule(
method: .get, // HTTP verb
path: "/posts/", // Endpoint
isAuthenticable: false, // Uses EasyRest Authenticated Service?
parameters: [:]) // query/path/header params? Header Body? Multipart form data? Put here!
case let .postsFilter(userId):
return Rule(
method: .get,
path: "/posts/",
isAuthenticable: false,
parameters: [.query: ["userId": "\(userId)"]])
case let .post(id):
return Rule(
method: .get,
path: "/posts/{id}/",
isAuthenticable: false,
parameters: [.path: ["id": id]])
case let .deletePost(id):
return Rule(
method: .delete,
path: "/posts/{id}/",
isAuthenticable: false,
parameters: [.path: ["id": id]])
case let .makePost(body):
return Rule(
method: .post,
path: "/posts/",
isAuthenticable: false,
parameters: [.body: body])
case let .editPost(id, body):
return Rule(
method: .put,
path: "/posts/{id}",
isAuthenticable: false,
parameters: [
.path: ["id": id],
.body: body,
.header: ["Content-type": "application/json; charset=UTF-8"]])
case let .editTitle(id, body):
return Rule(
method: .patch,
path: "/posts/{id}",
isAuthenticable: false,
parameters: [
.path: ["id": id],
.body: body,
.header: ["Content-type": "application/json; charset=UTF-8"]])
}
}
}
enum TestRoute: Routable{
case me(String)
case post(String)
var rule: Rule {
switch(self) {
case let .me(name):
return Rule(method: .get, path: "/api/v1/users/me/", isAuthenticable: true, parameters: [.query : ["name": name]])
case let .post(id):
let parameters : [ParametersType: AnyObject] = [:]
return Rule(method: .get, path: "/api/v1/posts/\(id)/", isAuthenticable: true, parameters: parameters)
}
}
}
服务示例
class TestRouteService : OAuth2Service<TestRoute> {
override var base: String { return BASE_URL }
override var interceptors: [Interceptor] { return [DefaultHeadersInterceptor()] }
convenience init() {
self.init()
}
func me(name: String, onSuccess: (result: Response<UserTest>?) -> Void, onError: (ErrorType?) -> Void, always: () -> Void) {
try! call(.me(name), type: UserTest.self, onSuccess: onSuccess, onError: defaultErrorHandler(onError), always: always)
}
func post(id: Int, onSuccess: (result: Response<Post>?) -> Void, onError: (ErrorType?) -> Void, always: () -> Void) {
try! call(.post(id), type: Post.self, onSuccess: onSuccess, onError: defaultErrorHandler(onError), always: always)
}
func defaultErrorHandler(onError: (ErrorType?) -> Void) -> (ErrorType?) -> Void {
return { error in
/* Do whatever is default for all errors, like
switch error.cause {
case .InternetConnection:
// backOff()
case .FailedJsonSerialization:
Crashlytics.sendMessage(error....)
Sentry.captureEvent(...)
}
*/
onError(error)
}
}
}
另外,我们也支持PromiseKit调用
class JsonPlaceholderService : Service<JsonPlaceholderRoutable> {
override public var base: String { return "https://jsonplaceholder.typicode.com" }
}
然后
let service = JsonPlaceholderService()
try! service.call(.post(id: 1), type: PostModel.self).promise
.done { result in
print("RESPONSE ITEM ID: \(result!.body!.id!)")
}.catch { error in
print("Error : \(error.localizedDescription)")
}.finally {
print("This code will be called all the time")
}
拦截器示例
class DefaultHeadersInterceptor : Interceptor {
required init() {}
func requestInterceptor<T: Codable>(_ api: API<T>) {
api.headers["Content-Type"] = "application/json"
api.headers["Accept"] = "application/json"
api.headers["Device-Token"] = "8ec3bba7de23cda5e8a2726c081be79204faede67529e617b625c984d61cf5c1"
api.headers["Device-Agent"] = "iOS_SANDBOX"
api.headers["Accept-Language"] = "pt-br"
}
func responseInterceptor<T: Codable, U>(_ api: API<T>, response: DataResponse<U>) {
}
}
待办事项
- 移除基因组并使用Swift 4 Codable
- 重试调用
- 发送请求以连接到互联网
- 为主功能创建单元测试
- 为可验证服务创建单元测试
- 为多部分数据上传创建单元测试
- 取消请求
- 创建一个维基库
- 添加响应模型以发送额外信息,如HTTP状态代码
- 文件上传
- 改进请求语法
- 错误处理程序
- 添加对AppCode中着色的支持
- 在内存中下载文件
- 直接将文件下载到存储(内存优化)
第三方库和引用
许可证
EasyRest可在MIT许可证下使用。有关更多信息,请参阅LICENSE文件。