Japx - JSON:API 解码器/编码器
轻量级的 JSON:API 解析器,它将复杂的 JSON:API 结构扁平化,并将其转换为简单的 JSON,反之亦然。它通过将 Dictionary
转换为 Dictionary
来工作,因此您可以使用 Codable、Unbox、Wrap、ObjectMapper 或者您喜欢的任何其他对象映射工具。
基本示例
对于给定的 JSON 对象示例
{
"data": {
"id": "1",
"type": "users",
"attributes": {
"email": "[email protected]",
"username": "john"
}
}
}
要将其解析为简单的 JSON,请使用
let jsonApiObject: [String: Any] = ...
let simpleObject: [String: Any]
do {
simpleObject = try JapxKit.Decoder.jsonObject(withJSONAPIObject: jsonApiObject)
} catch {
print(error)
}
解析器将将其转换为对象,其中所有属性都将展开到 data
对象的根目录中
{
"data": {
"email": "[email protected]",
"id": "1",
"username": "john",
"type": "users"
}
}
高级示例
解析关系
简单的 Article
对象,其中包含其 Author
{
"data": [
{
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
},
"relationships": {
"author": {
"data": {
"id": "42",
"type": "people"
}
}
}
}
],
"included": [
{
"type": "people",
"id": "42",
"attributes": {
"name": "John",
"age": 80,
"gender": "male"
}
}
]
}
将被展平为
{
"data": [
{
"updated": "2015-05-22T14:56:28.000Z",
"author": {
"age": 80,
"id": "42",
"gender": "male",
"type": "people",
"name": "John"
},
"id": "1",
"title": "JSON API paints my bikeshed!",
"created": "2015-05-22T14:56:29.000Z",
"type": "articles",
"body": "The shortest article. Ever."
}
]
}
解析附加信息
所有没有在JSON:API 规范中定义键的嵌套对象都将保持根对象内部的完整性(对于 links
和 meta
对象来说也是如此)
{
"data": [
{
"type": "articles",
"id": "3",
"attributes": {
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
}
}
],
"meta": {
"total-pages": 13
},
"links": {
"self": "http://example.com/articles?page[number]=3&page[size]=1",
"first": "http://example.com/articles?page[number]=1&page[size]=1",
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
"next": "http://example.com/articles?page[number]=4&page[size]=1",
"last": "http://example.com/articles?page[number]=13&page[size]=1"
},
"additional": {
"info": "My custom info"
}
}
解析后的 JSON
{
"data": [
{
"updated": "2015-05-22T14:56:28.000Z",
"id": "3",
"title": "JSON API paints my bikeshed!",
"created": "2015-05-22T14:56:29.000Z",
"type": "articles",
"body": "The shortest article. Ever."
}
],
"meta": {
"total-pages": 13
},
"links": {
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
"first": "http://example.com/articles?page[number]=1&page[size]=1",
"next": "http://example.com/articles?page[number]=4&page[size]=1",
"self": "http://example.com/articles?page[number]=3&page[size]=1",
"last": "http://example.com/articles?page[number]=13&page[size]=1"
},
"additional": {
"info": "My custom info"
}
}
使用包含列表解析
为了指定您想解析的嵌套对象,可以使用 includeList
参数。例如:
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
},
"relationships": {
"author": {
"data": {
"id": "42",
"type": "people"
}
}
}
},
"included": [
{
"type": "people",
"id": "42",
"attributes": {
"name": "John",
"age": 80,
"gender": "male"
},
"relationships": {
"article": {
"data": {
"id": "1",
"type": "articles"
}
}
}
}
]
}
Article
和 Author
可以通过引用,使用 JSON:API 规范中定义的包含来进行匹配。
let includeList: String = "author.article.author"
let jsonApiObject: [String: Any] = ...
let recursiveObject: [String: Any] = try JapxKit.Decoder.jsonObject(with: jsonApiObject, includeList: includeList)
解析后的 JSON
{
"data": {
"type": "articles",
"id": "1",
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z",
"author": {
"type": "people",
"id": "42",
"name": "John",
"age": 80,
"gender": "male",
"article": {
"type": "articles",
"id": "1",
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z",
"author": {
"type": "people",
"id": "42",
"name": "John",
"age": 80,
"gender": "male"
}
}
}
}
}
使用方法
Codable
Japx 为 Swift 的包装器 Swift Codable。
由于 JSON:API 对象可以拥有多个额外的字段,如元数据、链接或分页信息,因此其实际模型必须包装在 data
对象中。为了便于解析,还需要根据您的 API 规范创建封装的本地对象,该对象将包含您通用的 JSON 模型
struct JapxResponse<T: Codable>: Codable {
let data: T
// ... additional info like: meta, links, pagination...
}
struct User: JapxCodable {
let id: String
let type: String
let email: String
let username: String
}
let userResponse: JapxResponse<User> = try JapxDecoder().decode(JapxResponse<User>.self, from: data)
let user: User = userResponse.data
其中 JapxDecodable
和 JapxEncodable
在 JapxCodable
文件中定义,如下所示
/// Protocol that extends Decodable with required properties for JSON:API objects
protocol JapxDecodable: Decodable {
var type: String { get }
var id: String { get }
}
/// Protocol that extends Encodable with required properties for JSON:API objects
protocol JapxEncodable: Encodable {
var type: String { get }
}
可编码和Alamofire
Japx还提供了Alamofire和Codable的包装器,可以在安装章节中描述的方式中安装。
在DataRequest
上使用responseCodableJSONAPI
方法,它会将序列化的响应传递到回调中。此外,还有一个keyPath
参数,可以仅提取嵌套的data
对象。因此,如果您不需要除纯数据外的任何API侧信息,则可以创建简单对象,而无需使用包装对象/结构体。
struct User: JapxCodable {
let id: String
let type: String
let email: String
let username: String
}
Alamofire
.request(".../api/v1/users/login", method: .post, parameters: [...])
.validate()
.responseCodableJSONAPI(keyPath: "data", completionHandler: { (response: DataResponse<User>) in
switch response.result {
case .success(let user):
print(user)
case .failure(let error):
print(error)
}
})
可编码、Alamofire和RxSwift
Japx还提供了Alamofire、Codable和RxSwift的包装器,可以在安装章节中描述的方式中安装。
使用DataRequest
的.rx
扩展上的responseCodableJSONAPI
方法,它会返回一个带有序列化响应的Single
。
let loginModel: LoginModel = ...
let executeLogin: ([String: Any]) throws -> Single<User> = {
return Alamofire
.request(".../api/v1/users/login", method: .post, parameters: $0)
.validate()
.rx.responseCodableJSONAPI(keyPath: "data")
}
return Single.just(loginModel)
.map { try JapxEncoder().encode($0) }
.flatMap(executeLogin)
安装
Cocoapods
Japx可通过CocoaPods获得。要安装它,只需将以下行添加到您的Podfile中
pod 'Japx'
我们还添加了一些更多功能,例如用于网络通信的Alamofire或Moya、用于响应式编程的Rx,以及Objective-C支持。
# Alamofire
pod 'Japx/Alamofire'
# Alamofire and RxSwift
pod 'Japx/RxAlamofire'
# Moya
pod 'Japx/Moya'
# Moya and RxSwift
pod 'Japx/RxMoya'
# Objective-C
pod 'Japx/ObjC'
与其他依赖管理器不同,您应该始终使用
import Japx
无论您选择哪种自定义集成。
注意:由于与Rx支持的问题,Japx 4.0.0版本指向Moya的development
分支。如果您需要稳定的Moya支持,请使用版本3.0.0。否则,请将Podfile指向开发Moya。
platform :ios, '10.0'
use_frameworks!
target 'MyApp' do
pod 'Moya', :git => "https://github.com/Moya/Moya.git", :branch => "development"
pod 'Japx/RxMoya'
end
Swift 包管理器
将依赖项添加到您的 Package.swift
文件中,然后在您的目标中使用
dependencies: [
.package(url: "https://github.com/infinum/Japx.git", .upToNextMajor(from: "4.0.0"))
]
示例 Package.swift
let package = Package(
name: "YourDependency",
products: [
.library(name: "YourDependency", targets: ["YourDependency"])
],
dependencies: [
.package(url: "https://github.com/infinum/Japx.git", .upToNextMajor(from: "4.0.0")),
],
targets: [
.target(
name: "YourDependency",
dependencies: [.product(name: "Japx", package: "Japx")]
)
]
)
我们还添加了一些其他功能,例如用于网络通信的 Alamofire 或 Moya,用于响应式编程的 Rx
// Alamofire
.product(name: "JapxAlamofire", package: "Japx")
// Alamofire and RxSwift
.product(name: "JapxRxAlamofire", package: "Japx")
// Moya
.product(name: "JapxMoya", package: "Japx")
// Moya and RxSwift
.product(name: "JapxRxMoya", package: "Japx")
根据您选择的产品,您需要导入不同的模块
// Pure Japx
import Japx
// Alamofire
import JapxAlamofire
// Alamofire and RxSwift
import JapxRxAlamofire
// Moya
import JapxMoya
// Moya and RxSwift
import JapxRxMoya
Carthage
运行 carthage update --use-xcframeworks
并导入所需的集成。纯 Japx
没有任何依赖项。
导入方式与 Swift 包管理器相同,具体取决于您选择的集成方式。
注意:由于最新的 Moya 构建不与 Carthage 配合使用,因此 Moya 集成目前不支持通过 Carthage。更多信息请查看这里。
示例项目
您可以在 Nuts And Bolts 仓库 中找到使用 Codable 和 Alamofire 实现 Japx 网络的示例项目,其中包含常用代码。示例项将介绍如何使用 Japx 和 JSON:API 格式处理基本的 CRUD (创建、读取、更新、删除) 操作。要运行示例,请在 仓库 上克隆,打开 Catalog.xcworkspace
,运行 Catalog 应用并在 Japx 网络部分中进行导航。
该仓库中还包括一个简单的示例项目,要运行它,请打开 Japx.xcodeproj
并检查 Example
目录以及 Japx_Example 架构。
在 Examples
目录中可以找到与 Cocoapods (运行 pod install
)、Swift 包管理器以及 Carthage 的基本集成。
作者
- Vlaho Poluta, [emailischer][-typing here-]
- Filip Gulan, [emailischer][-typing here-]
由 Infinum 维护
许可证
Japx可在MIT许可证下使用。有关更多信息,请参阅LICENSE文件。