SwiftRestful 0.0.4

SwiftRestful 0.0.4

Acidmanic 维护。



Swift Restful

CI Status Version GitHub license Platform

关于

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()方法。

中断截获

使用拦截器,可以在发送请求之前更改请求参数。最常见的例子是将授权令牌添加到请求标头中。为此,您可以创建一个实现协议的类。然后在onRequest()方法中,您可以对requestParam对象进行任何需要的更改。目前不支持在http请求截获中拒绝请求。

示例代码

使用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
            
}

本例中提到的类是一个具有四个字段(标题、正文、userId和id)的简单类。您可以在SwiftRestfulTests/TestModels/Todo.swift中找到其定义。

使用发布对象,接收对象

    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
    }

您还可以使用.putTodoichApiClient.delete.补丁来更新、删除和部分更新任务。

使用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
    }
}

这个用户类现在可以用来向服务器发送或从服务器接收数据,使用的是 HttpApiClientCrudClient。但是当字段数量和类型种类增加时,将这些值转换为每个字段所需的形式变得更加困难。另一方面,我们可能想要支持多种命名约定,以便在命名约定不一致的情况下覆盖后端。为了使这种转换更容易并且支持多种命名约定,您可以从 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。所以如果您在下层设置全局拦截器,所有高层的都会受到影响。

感谢 & 祝好运👍 Mani