RestService - 为 iOS 项目提供的一个轻量级 REST 服务框架
TL; DR
RestService
是基于 URLRequest
的一个轻量级 REST 服务,在上面添加了一些基础功能。看看这个
let service = RestService(host: "api.github.com")
let task = service.json(
method: .get,
path: "/users/ricardorauber/repos",
responseType: [Repository].self) { response in
switch response {
case .success(let repositories):
print("cool!", repositories)
case .failure:
print("oh no!")
}
}
REST Service
大家好,感谢您来!您能到这里来是因为您正在寻找一种可以帮助您在应用中实现 HTTP 请求的工具,对吗?这正是这个框架所做的事情,希望它会成功地融入您的项目中。您可能会想,为什么还需要另一个服务,与像 Alamofire 这样的优秀框架相比有什么优势呢?嗯,当然,市面上有很多解决方案,它们确实很棒。唯一的问题是它们提供了太多的可能性,而我只想建立一个简单、安全且易于使用的框架。让我向您展示它是如何工作的,然后您将决定它是否是您的好选择。
设置
CocoaPods
如果您使用CocoaPods,请将其添加到您的Podfile中,并运行pod install
。
target 'Your target name' do
pod 'RestService', '~> 2.3'
end
手动安装
如果您想手动将其添加到项目中,不使用包管理器,只需将所有文件从Classes
文件夹复制到您的项目中。
使用方法
创建服务
为了创建服务实例,您只需导入框架,并使用您的主机实例化RestService
。比如说,您的主机是https://server.com/
import RestService
let service = RestService(host: "server.com")
这样就会创建一个使用https
方案的服务。但如果您需要使用其他方案,您可以为此服务添加更多信息
import RestService
let service = RestService(
session: URLSession.shared,
encoder: JSONEncoder(),
decoder: JSONDecoder(),
scheme: .http,
host: "localhost",
port: 3000,
basePath: "/api"
)
这样它将创建一个针对https://:3000/api
的服务。
请注意,所有这些属性以后都可以修改。
设置basePath
参数为所有请求设置基本路径,所以如果您请求/users
路径,例如,它将发送到https://:3000/api/users
。
您也可以使用一个URL
值或甚至是String
作为URL
import RestService
let urlService = RestService(url: URL(string: "https://server.com:3000")!)
let stringService = RestService(url: "https://server.com:3000")
发送简单的JSON请求
现在您已创建服务,是时候进行一些请求了。让我们从一个非常简单的GET
请求开始,针对api/users
端点。
service.json(
method: .get,
path: "/api/users") { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
看这个?很简单!
使用参数发送 JSON 请求
现在让我们用参数发送一个请求,但在做之前,我们需要明确一下这些参数。当您发送 GET
、HEAD
和 DELETE
请求时,您将通过查询字符串发送参数,但对于所有其他方法,您将在请求体中发送参数。据此,RestService
将根据您为该请求选择的方法设置正确的属性。
这里还有一点是,您要决定是否要使用简单的字典或 Encodable
对象作为参数。我个人更喜欢 Encodable
对象,因为编译器将会对您的参数名称中的拼写错误发出警告,而且编写 API 逻辑会更好。
所以,让我们使用字典作为参数发送一个 GET
请求
let parameters: [String: Any] = [
"username": "john",
"limit": 10,
"offset": 0
]
service.json(
method: .get,
path: "/api/users",
parameters: parameters) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
发生了什么事?嗯,它确实创建了一个请求,这个网址没有请求体:https://server.com/api/users?username=john&limit=10&offset=0
关于 POST
请求呢?让我们用 Encodable
对象来演示一下!
struct CreateUserRequest: Codable {
let username: String
let password: String
}
let parameters = CreateUserRequest(username: "john", password: "safepassword")
service.json(
method: .post,
path: "/api/users",
parameters: parameters) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
这样,它创建了一个 targeted POST
请求,网址为 https://server.com/api/users
,并且带有了这个 JSON
请求体
{
"username": "john",
"password": "safepassword"
}
厉害吧?
使用参数发送 FORM/DATA 请求
如果您需要以 form/data
格式发送请求,您可以使用一些 FormDataParameters
很容易地发送它。您可以创建一个 FileFormDataParameter
或一个 TextFormDataParameter
。
所以,让我们用一些参数发送一个 POST
请求
let parameters: [FormDataParameter] = [
TextFormDataParameter(name: "id", value: "10"),
TextFormDataParameter(name: "email", value: "[email protected]"),
FileFormDataParameter(name: "text", filename: "text.txt", contentType: "text/plain", data: textData),
FileFormDataParameter(name: "image", filename: "thumb.png", contentType: "image/png", data: imageData)
]
service.formData(
method: .post,
path: "/api/userdata",
parameters: parameters) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
使用参数发送表单 URL 编码请求
这是另一种类似于 x-www-form-urlencoded
的请求,就像 JSON
请求一样容易。
let parameters: [String: Any] = [
"username": "john",
"password": "12345"
]
service.formUrlEncoded(
method: .post,
path: "/api/login",
parameters: parameters) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
使用数据体发送简单请求
好的,你未使用任何列出的请求类型,但你仍然想使用 RestService
发送请求?当然,这非常简单,只需要将正文发送为 Data
service.request(
method: .post,
path: "/api/upload",
body: body) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
使用拦截器进行请求
拦截器是修改请求(在将其发送到服务器之前)的绝佳方式。这是一个添加类似身份验证令牌等头部的绝佳机会。让我们看看它是如何工作的!
struct TokenInterceptor: RequestInterceptor {
func adapt(request: URLRequest) -> URLRequest {
var request = request
request.addValue("Bearer gahsjdGJSgdsajagA", forHTTPHeaderField: "Authorization")
return request
}
}
let interceptor = TokenInterceptor()
service.json(
method: .get,
path: "/api/me",
interceptor: interceptor) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
这将在执行前将令牌添加到请求中。拦截器可以重复使用,非常适合添加服务器所需的所有东西。
如果你需要添加多个拦截器,可以使用 RestInterceptorGroup
struct APIKeyInterceptor: RequestInterceptor {
func adapt(request: URLRequest) -> URLRequest {
var request = request
request.addValue("12345", forHTTPHeaderField: "X-API-KEY")
return request
}
}
struct TokenInterceptor: RequestInterceptor {
func adapt(request: URLRequest) -> URLRequest {
var request = request
request.addValue("Bearer gahsjdGJSgdsajagA", forHTTPHeaderField: "Authorization")
return request
}
}
let interceptor = GroupInterceptor(interceptors: [
APIKeyInterceptor(),
TokenInterceptor()
])
service.json(
method: .get,
path: "/api/me",
interceptor: interceptor) { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
处理来自服务器的响应
很多人遇到的问题是服务器响应。类型转换,序列化,解码……选择无限。我尝试通过这个框架实现的是,以你需要的数据形式获得漂亮的响应。
有 4 种响应可能性
无正文
如果你只需发送请求,并且不期望获得任何对象作为响应,那么你只需像之前看到的那样调用即可
service.json(
method: .get,
path: "/api/me") { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
带有响应类型
现在假设你需要将响应正文转换为 Codable
对象,当请求成功时
struct Person: Codable {
let id: Int
let name: String
}
service.json(
method: .get,
path: "/api/me",
responseType: Person.self) { response in
switch response {
case .success(let person):
print("success!", person)
case .failure:
print("failure")
}
}
来自服务器的自定义错误
如果你的Web服务以自定义方式返回错误,比如返回一个包含错误详情的json对象,你可以使用另一个参数来将响应解码为Codable
对象,如下所示
struct ServerError: Codable {
let code: Int
let message: String
}
service.json(
method: .get,
path: "/api/me",
customError: ServerError.self) { response in
switch response {
case .success:
print("success!")
case .customError(let error):
print("server error", error)
case .failure:
print("failure")
}
}
全部包含:响应类型 + 自定义来自服务器的错误
最后,你可以将所有内容放在一起,成功的响应类型、来自服务器的自定义错误和通用的失败响应
struct Person: Codable {
let id: Int
let name: String
}
struct ServerError: Codable {
let code: Int
let message: String
}
service.json(
method: .get,
path: "/api/me",
responseType: Person.self,
customError: ServerError.self) { response in
switch response {
case .success(let person):
print("success!", person)
case .customError(let error):
print("server error", error)
case .failure:
print("failure")
}
}
处理任务的进度
很酷的事情是,使用RestService
你可以处理任何类型任务(而不仅仅是JSON)的进度,例如更新UI
service.json(
method: .get,
path: "/api/me",
progress: { value in
print("progress:", value)
},
completion: { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
)
调试/日志
最后但同样重要的是,作为开发者,我们经常需要调试一些请求,并且通常需要付出一定的努力来使其变得漂亮,因此我做了一些酷的事情让您的生命变得更加简单
let service = RestService(debug: true, host: "api.github.com")
只需在创建服务时添加debug
参数并将其设置为true
,您将看到所有请求都在Xcode控制台中记录。很棒,对吧?但这还不是全部,您可以将单个请求的调试设置为
service.json(
debug: true,
method: .get,
path: "/api/me",
completion: { response in
switch response {
case .success:
print("success!")
case .failure:
print("failure")
}
}
)
它看起来是什么样子?以下是一个小样本
==============================================
⚪️ REQUEST: https://api.github.com/users/ricardorauber/repos
> Headers:
[
"Content-Type": "application/json; charset=utf-8"
]
> Body:
nil
🟢 RESPONSE: 200
> Headers:
[
"referrer-policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
"x-github-media-type": "github.v3; format=json",
"Status": "200 OK",
...
]
> Body:
[{"id":253579430,"node_id":"MDEwOlJlcG9zaXRvcnkyNTM1Nzk0MzA="}]
------------------------------
👍
谢谢本框架的创建得益于这些优秀的人们
- Gray公司:https://www.graycompany.com.br/
- Swift by Sundell:https://www.swiftbysundell.com/
- Hacking with Swift:https://www.hackingwithswift.com/
- Ricardo Rauber:http://ricardorauber.com/
欢迎反馈
如果您发现任何问题,卡住了,或者只是想聊天,请随意创建一个问题。我们将很高兴为您提供帮助。
许可证
RestService是在MIT许可证下发布的。