Swift Restful
关于
Swift Restful 项目提供了一些有用的 HTTP 访问类和工具,希望这将使 API 调用变得更容易。它还介绍了一种在幕后完成对象序列化(从/到 JSON 字符串)的方法。目标是让用户能够以 DTO 调用 API 并自动接收 DTO 作为响应。
特性
- 异步 HTTP 调用
- 应用范围和对象范围内的拦截
- 直接使用 DataTransfer 对象发送/接收数据
- 接受来自多个命名规范的 DTO
- OAuth 支持
如何获取库
- Cocoapods
SwiftRestful可通过CocoaPods获得。要安装它,只需将以下行添加到 Podfile 中
pod 'SwiftRestful'
- Carthage
要使用 Carthage 获取库的最新版本,可以将以下行添加到 Cartfile。
github "Acidmanic/SwiftRestful"
如何使用
灵活 | 低级别访问
要调用用于获取<强>原始数据强>的HTTP端点,您将使用最简单的类:<强>HttpClient强>。HttpClient包装Swift内部的HTTP访问类。它提供了一个download()方法,可以为http请求参数添加任何数据,并使用任何http方法(GET/POST/PUT/...)写入数据。它更灵活,但不是调用HTTP端点的最简单方式,通常用于进行HttpApiClient类未涵盖的特殊调用。
API调用 | 简单容易!
要调用HTTP端点,<强>发送字符串主体、URL参数、WWW表单参数或您的数据对象,并将返回原始字符串或数据对象强>,您应使用<强>HttpApiClient强>。该类使用流畅的语法且易于使用。它主要用于进行API调用。
RESTful CRUD端点
如果您在API端点有一个<强>完全RESTful强>的资源,您可以使用<强>CrudClient强>类。这个类主要基于约定操作。它使用HTTP方法来获取服务器上的对象,添加、删除和更新它们。使用<强>CrudClient强>,您将不会处理HTTP协议,而只需使用创建、读取、更新和删除方法。
OAuth
由于RESTful资源通常受保护,访问它们需要授权。您需要在请求中添加授权标题,使用拦截器可以轻松完成。但首先,您需要登录到您的授权服务器并接收令牌。为此,您可以使用OAuthClient类。该类提供了login()、refresh()和revoke()方法。
中断截获
使用拦截器,可以在发送请求之前更改请求参数。最常见的例子是将授权令牌添加到请求标头中。为此,您可以创建一个实现
示例代码
使用HttpClient下载Html页面
let client = HttpClient()
client.download(url: "http://www.google.com", method:HttpMethod.GET,
headers:[:],contentData:nil){ (result:HttpResponse<Data>) in
let sResult = String(data:result.Value,encoding:result.ResponseCharsetEncoding)
print(sResult)
}
使用HttpApiClient
let client = HttpApiClient()
client.get.url("http://www.google.com").request(){(result:HttpResponse<String>) in
print(result.Value)
}
使用HttpApiClient获取对象
let client = HttpApiClient()
client.get.url("http://jsonplaceholder.typicode.com/todos/12")
.request(){(result:HttpResponse<Todo>) in
// take any action needed with received object
let todoObject = result.Value
}
本例中提到的
使用
let client = HttpApiClient()
let todo = Todo(title: "NewTodo", body: "TestObject", userId: 123)
client.post.url("http://jsonplaceholder.typicode.com/todos")
.jsonData(todo).request(){(result:HttpResponse<Todo>) in
// take any action needed with received object
let todoObject = result.Value
}
使用xwwwForm发送数据
let client = HttpApiClient()
client.post.url("http://jsonplaceholder.typicode.com/todos")
.xwwwFormData(["title":"NewTodo","body":"dodo","userId":"123"])
.request(){(result:HttpResponse<Todo>) in
// take any action needed with received object
let todoObject = result.Value
}
您还可以使用
使用Crud客户端从服务器获取Id=12的对象
let client = CrudClient(endpoint: "http://jsonplaceholder.typicode.com/todos")
client.read(params: ["id":"12"]) { (result:Todo!) in
// if successful, result is the object
// if not, then result will be nil
}
一个crud创建示例
let client = CrudClient(endpoint: "http://jsonplaceholder.typicode.com/todos")
let createdTodo = Todo(title: "NetworkTest", body: "PerformNetworkTest", userId: 123)
client.create(object: createdTodo){(result:Todo) in
// if successful, the result will be created objec
// usually with its id set. and in case of unsuccessful
// call, result will be nil.
}
和crud删除示例
这将尝试从http://reqres/api/users中删除id = 12的用户
let client = CrudClient(endpoint: "http://reqres.in/api/users")
client.delete(params: ["id":"12"]){(succeed:Bool) in
// 🤔 pretty clear, right?
}
定义您的数据对象传输
为了使您的DTO能够轻松在此库的http客户端类中使用,这些类应遵守Jsonable协议。这意味着它们负责从给定的json数据中填充自己的字段。这个给定的json数据实际上是Swift半反序列化产生的字典。让我们看看一个例子
class User:Jsonable{
var name:String!
var email:String!
required init(){}
func load(jsonData: JsonMediumType!) {
self.name = jsonData["name"] as? String
self.email = jsonData["email"] as? String
}
}
这个用户类现在可以用来向服务器发送或从服务器接收数据,使用的是 HttpApiClient 或 CrudClient。但是当字段数量和类型种类增加时,将这些值转换为每个字段所需的形式变得更加困难。另一方面,我们可能想要支持多种命名约定,以便在命名约定不一致的情况下覆盖后端。为了使这种转换更容易并且支持多种命名约定,您可以从 NamingRitchJsonable 基类派生您的 DTO 类。这样,您将有权访问字段(getString(),getInt(),getDouble()...)的转换方法。您还可以选择您想接受哪种命名约定。转换方法将使用这些约定来解析字段名称并从 jsonData 中选择正确的数据片段。
示例
class User:NamingRitchJsonableBase,Jsonable{
var name:String!
var email:String!
var id:Int!
required override init(){
self.acceptingNamingConventions =
[NamingConventions.CamelCase,NamingConventions.PascallCase]
}
func load(jsonData: JsonMediumType!) {
self.name = getString(jsonData,"name")
self.email = getString(jsonData,"email")
self.id = getInt(jsonData,"id")
}
}
这样,两个 JSON 字符串:{"name":"mani","email":"[email protected]","id":12}
和 {"Name":"mani","Email":"[email protected]","Id":12}
都将被解析为具有有效值的相同对象。
Jsonabe 支持嵌套 Jsonabe 类。您可以在每个 Jsonable 对象中设置 Jsonable 字段,并且转换将正常工作。例如,考虑我们的用户有一个 Todo 对象字段。然后它看起来像
class User:NamingRitchJsonable,Jsonable{
var name:String!
var email:String!
var id:Int!
var todo:Todo!
required override init(){
self.acceptingNamingConventions =
[NamingConventions.CamelCase,NamingConventions.PascallCase]
}
func load(jsonData: JsonMediumType!) {
self.name = getString(jsonData,"name")
self.email = getString(jsonData,"email")
self.id = getInt(jsonData,"id")
self.todo = getJsonable(jsonData,"todo")
}
}
OAuth
目前 OAuthClient 类可以使用 password grant_type 来执行登录,可以通过用户名和密码登录,刷新之前收到的令牌,并撤销令牌。
let client = OAuthClient(baseUrl: "", clientId: "TestClient" , clientSecret:"secret")
client.login(url: "https://apifest-live.herokuapp.com/oauth20/tokens"
, username: "mani", password: "mani") { (result:HttpResponse<LoginResult>) in
if HttpClient.isReponseOK(code: result.ResponseCode){
// provided access_token :
let access_token = result.Value.access_token
}
}
刷新令牌
let client = OAuthClient(baseUrl: "", clientId: "TestClient" , clientSecret:"secret")
client.refresh(url: "https://apifest-live.herokuapp.com/oauth20/tokens"
, refreshToken: "mani") { (result:HttpResponse<LoginResult>) in
if HttpClient.isReponseOK(code: result.ResponseCode){
// provided access_token :
let access_token = result.Value.access_token
}
}
撤销令牌
let client = OAuthClient(clientId: "TestClient" , clientSecret:"secret")
client.revoke(url: "https://apifest-live.herokuapp.com/oauth20/tokens/revoke",
accessToken: "mani") { (result:Bool) in
// succeeded = result
}
授权拦截
要为来自特定客户端的所有请求添加授权令牌,首先您应该创建一个拦截器类。例如
public class AuthorizationInterceptor:HttpRequestInterceptor{
var accessToken:String!
public func onRequest(requestParams:HttpRequestParameters)->HttpRequestParameters{
if self.accessToken != nil {
requestParams.headers[HttpHeaderCollection.Authorization]
= HttpHeaderCollection.AuthorizationBearerPrefix + self.accessToken
}
return requestParams
}
}
这可能是一个共享对象,或一个单例等。您可以将此类对象推入客户端拦截器中。拦截器可以添加到客户端或应用于客户端类的所有实例。
let interceptor = AuthorizationInterceptor()
interceptor.accessToken = "mani"
// add interceptor to current client only
client.pushInstanceInterceptor(interceptor:interceptor)
let interceptor = AuthorizationInterceptor()
interceptor.accessToken = "mani"
// add interceptor to any request that is beeing made by a CrudClient object
CrudClient.pushGlobalInterceptor(interceptor:interceptor)
// add interceptor to any request that is beeing made with all ApiClients and therefore all CrudClients *
HttpApiClient.pushGlobalInterceptor(interceptor:interceptor)
// add interceptor to any request that is beeing made with this library *
HttpClient.pushGlobalInterceptor(interceptor:interceptor)
- CrudClient 对象在内部使用 HttpApiClients,而 HttpApiClients 在内部使用 HttpClients。所以如果您在下层设置全局拦截器,所有高层的都会受到影响。
感谢 & 祝好运