SwiftDecodePipeline 0.0.3

SwiftDecodePipeline 0.0.3

测试已测试
语言语言 SwiftSwift
许可 MIT
发布上次发布2017年5月
SwiftSwift版本3.0
SPM支持 SPM

Héctor Ramón Jiménez维护。



 
依赖于
SwiftyJSON~> 3.0
Curry~> 3.0
 

  • Héctor Ramón Jiménez

SwiftDecodePipeline

一个用于使用管道操作符((|>))和普通函数调用构建JSON解码器的库。受到elm-decode-pipeline的启发。

动机

作为一名Swift的新手,我并不完全相信现有的JSON解码库。在尝试了Elm之后,我希望可以得到一些简单且主要基于函数的库。

Argo引起了我的注意。虽然它在很大程度上符合我的需求,但它强制你在你的类型中实现一个decode方法。这样做允许Argo自动解码任何实现了Decodable协议的类型。但是,这种方法不够灵活。它将一个(且仅一个)解码器绑定到特定的类型,永久不可更改。如果我们想将不同API的响应解码为同一个类型怎么办?如果某些端点不返回完全相同的数据怎么办?这是否听起来很熟悉?另外,Argo使用了许多不同的中缀操作符(如<^><*><|<||),这使得解码器定义难以理解和推理。

我认为解码器应该是独立的纯净函数,它们从类型中独立存在。它们接收一些数据(目前为JSON)并产生一个错误或某个类型的实例。解码器应该容易组合和重用,而这只需要一个简单的中缀操作符:管道操作符(|>)。这种方法在elm-decode-pipeline中得到了很好的实现,这是一个Elm语言库,它产生了简单、可读和可重用的解码器。

SwiftDecodePipeline试图将elm-decode-pipeline的精神带入Swift。

## 示例

假设我们有一个这个类型

struct User {
    let name: String
    let surname: String
    let image: String?
    let score: Int
    let sports: [String]
    let role: String
}

我们需要解码一些API端点/users返回的数据,如下所示

[
    {
        "uuid": "...",
        "name": "John",
        "last_name": "Doe",
        "image": null,
        "sports": ["basketball", "tennis"],
        "score": 5
    }
]

然后我们可以为该端点轻松编写一个Decoder<User>

let decodeUser: Decoder<User> =
    decode(User.init)
        |> required("name", string)
        |> required("last_name", string)
        |> optional("image", string)
        |> required("score", int)
        |> required("sports", array(string))
        |> hardcoded("athlete")

现在我们可以解码响应

let data: String!

// We make a request to /users and obtain the JSON here...

let result = decodeJSON(data, with: array(decodeUser))

switch result {
case .error(let error): print("Invalid format: \(error)") // error describes the decoding error
case .ok(let users): doSomething(with: users) // users has type [User] :D
}

在上面的示例中,data 是一个 String。然而,decode 函数支持不同的类型作为第一个参数以适应您的需求。下一节将描述可以使用此库解码的不同数据类型。

注意将解码器转换和重复使用的简单性。在这种情况下,我们的 decodeUser 可以解码单个用户,但我们想解码一串用户。因此,我们最终使用 array(decodeUser) 将我们的 Decoder 转换为 Decoder<[User]>。一个 Decoder 在格式无效时返回 .error(String),或者在输入成功解码时返回 .ok(Type)

## 可用函数 ### decodeJSON(json, with: decoder)

它允许以便捷的方式在 JSON 解码中使用解码器。目前,有 3 个不同的 decodeJSON 定义。它们接受 JSON 的不同形式:DataStringAny

Any 定义是为了 支持 Alamofire 响应数据

原始数据类型

原始数据类型本身就是解码器。它们将 JSON 值解码为 Swift 值。

let string: Decoder<String> 
let bool:   Decoder<Bool>
let int:    Decoder<Int>
let double: Decoder<Double>

### 修饰符

修饰符是一个可以接收一些配置参数并返回一个函数的函数,该函数可以接收一个解码器并返回一个新的解码器,该解码器具有一些附加行为。

在本节中,使用 <modifier>(<configParams>) 语法来描述不同修饰符。

required(String, Decoder)optional(String, Decoder)

required 从 JSON 对象中提取一个字段并解码其值为 A,如果字段不存在或为 null 则失败。optional 会执行相同的操作,同时允许字段缺失或为 null,因此解码为 A?

struct User {
    let name: String
    let image: String?
}

let decodeUser: Decoder<User> =
    decode(User.init)
        |> required("name", string)
        |> optional("image", string)

array

它解码 JSON 数组。

struct Post {
    // ...
    let authors: [User]
    // ...
}

let decodePost: Decoder<Post> =
    decode(Post.init)
        //...
        |> required("authors", decodeUser |> array)
        // We could use array(decodeUser), they are equivalent
        // ...

hardcoded(A)

它总是返回提供的值,独立于 JSON 数据。它用于在解码管道中硬编码数据。

let decodeMockedUser: Decoder<User> =
    decode(User.init)
        |> hardcoded("some-id")
        |> hardcoded("John")
        |> hardcoded("Doe")
        // ...

map((A) -> B)

它将解码值从 A 转换为 B

let decodeLowercasedString: Decoder<String> = string |> map { $0.lowercased }

## 库支持

Alamofire

此库可以轻松与 Alamofire 一同使用

Alamofire.request("https://example.com/users").validate().responseJSON { response in
    switch response.result {
    case .success(let data):
        // We want to decode a list of users, so we use array
        let decodingResult = decodeJSON(data, with: array(decodeUser))

        switch decodingResult {
        case .error(let error): print("Invalid format: \(error)") // error describes the decoding error
        case .ok(let users): doSomething(with: users) // users has type [User]
        }
    // Handle request error here...
    }
}

### SwiftyJSON

此库内部使用 SwiftyJSON。您应该能够直接使用解码器解码 JSON 类型。

let json: JSON!
let result = decodeUser(json)

安装

SwiftDecodePipeline 可通过 CocoaPods 使用。要安装它,请将以下行添加到您的 Podfile 中

pod 'SwiftDecodePipeline'

作者

Héctor Ramón Jiménez

许可证

SwiftDecodePipeline 在 MIT 许可证下提供。有关更多信息,请参阅 LICENSE 文件。

## 贡献

  1. Fork 存储库。
  2. 进行您的更改,测试将被欣赏。
  3. 在此存储库中打开拉取请求。

特别提及其他(并感谢)

  • SwiftyJSON,因为它使用非常方便,并且这个库内部使用了它。
  • Curry,另一个在幕后使用的酷库。
  • Argo
  • Elm