# Japx
**Repository Path**: kekekele/Japx
## Basic Information
- **Project Name**: Japx
- **Description**: 为github的Japx镜像工程
- **Primary Language**: Swift
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-07-18
- **Last Updated**: 2022-07-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Japx - JSON:API Decoder/Encoder
[](https://app.bitrise.io/app/76e0e1ec75e38509)
[](http://cocoapods.org/pods/Japx)
[](http://cocoapods.org/pods/Japx)
[](http://cocoapods.org/pods/Japx)
Lightweight [JSON:API][1] parser that flattens complex [JSON:API][1] structure and turns it into simple JSON and vice versa.
It works by transferring `Dictionary` to `Dictionary`, so you can use [Codable][2], [Unbox][3], [Wrap][4], [ObjectMapper][5] or any other object mapping tool that you prefer.
- [Japx - JSON:API Decoder/Encoder](#japx---jsonapi-decoderencoder)
- [Basic example](#basic-example)
- [Advanced examples](#advanced-examples)
- [Parsing relationships](#parsing-relationships)
- [Parsing additional information](#parsing-additional-information)
- [Parsing with include list](#parsing-with-include-list)
- [Usage](#usage)
- [Codable](#codable)
- [Codable and Alamofire](#codable-and-alamofire)
- [Codable, Alamofire and RxSwift](#codable-alamofire-and-rxswift)
- [Installation](#installation)
- [Cocoapods](#cocoapods)
- [Swift Package Manager](#swift-package-manager)
- [Carthage](#carthage)
- [Example project](#example-project)
- [Authors](#authors)
- [License](#license)
## Basic example
For given example of JSON object:
```json
{
"data": {
"id": "1",
"type": "users",
"attributes": {
"email": "john@infinum.co",
"username": "john"
}
}
}
```
to parse it to simple JSON use:
```swift
let jsonApiObject: [String: Any] = ...
let simpleObject: [String: Any]
do {
simpleObject = try JapxKit.Decoder.jsonObject(withJSONAPIObject: jsonApiObject)
} catch {
print(error)
}
```
and parser will convert it to object where all properties inside `attributes` object will be flattened to the root of `data` object:
```json
{
"data": {
"email": "john@infinum.co",
"id": "1",
"username": "john",
"type": "users"
}
}
```
## Advanced examples
### Parsing relationships
Simple `Article` object which has its `Author`:
```json
{
"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"
}
}
]
}
```
will be flattened to:
```json
{
"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."
}
]
}
```
### Parsing additional information
All nested object which do not have keys defined in [JSON:API Specification][6] will be left inside root object intact (same goes for `links` and `meta` objects):
```json
{
"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"
}
}
```
Parsed JSON:
```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"
}
}
```
### Parsing with include list
For defining which nested object you want to parse, you can use `includeList` parameter. For example:
```json
{
"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` and `Author` can be matched using include reference, as defined in [JSON:API Specification][6]:
```swift
let includeList: String = "author.article.author"
let jsonApiObject: [String: Any] = ...
let recursiveObject: [String: Any] = try JapxKit.Decoder.jsonObject(with: jsonApiObject, includeList: includeList)
```
Parsed JSON:
```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"
}
}
}
}
}
```
## Usage
### Codable
Japx comes with wrapper for _Swift_ [Codable][7].
Since JSON:API object can have multiple additional fields like meta, links or pagination info, its real model needs to be wrapped inside `data` object. For easier parsing, also depending on your API specification, you should create wrapping native object which will contain your generic JSON model:
```swift
struct JapxResponse: 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 = try JapxDecoder().decode(JapxResponse.self, from: data)
let user: User = userResponse.data
```
where `JapxDecodable` and `JapxEncodable` are defined in `JapxCodable` file as:
```swift
/// 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 }
}
```
### Codable and Alamofire
Japx also comes with wrapper for [Alamofire][10] and [Codable][7] which can be installed as described in [installation](#installation) chapter.
Use `responseCodableJSONAPI` method on `DataRequest` which will pass serialized response in callback. Also, there is `keyPath` argument to extract only nested `data` object. So, if you don't need any additional info from API side except plain data, than you can create simple objects, without using wrapping objects/structs.
```swift
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) in
switch response.result {
case .success(let user):
print(user)
case .failure(let error):
print(error)
}
})
```
### Codable, Alamofire and RxSwift
Japx also comes with wrapper for [Alamofire][10], [Codable][7] and [RxSwift][11] which can be installed as described in [installation](#installation) chapter.
Use `responseCodableJSONAPI` method from `.rx` extension on `DataRequest` which will return `Single` with serialized response.
```swift
let loginModel: LoginModel = ...
let executeLogin: ([String: Any]) throws -> Single = {
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)
```
## Installation
### Cocoapods
Japx is available through [CocoaPods][8]. To install it, simply add the following line to your Podfile:
```ruby
pod 'Japx'
```
We've also added some more functionalites like Alamofre or Moya for networking, Rx for reactive programming approach, Objective-C support:
```ruby
# 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'
```
Unlike with other dependency managers below, you should always use:
```swift
import Japx
```
regardless of which custom integration you've picked.
```ruby
platform :ios, '10.0'
use_frameworks!
target 'MyApp' do
pod 'Japx/RxMoya'
end
```
### Swift Package Manager
Add the dependency to your `Package.swift` and use in your target
```swift
dependencies: [
.package(url: "https://github.com/infinum/Japx.git", .upToNextMajor(from: "4.0.0"))
]
```
Sample `Package.swift`
```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")]
)
]
)
```
We've also added some more functionalites like Alamofre or Moya for networking, Rx for reactive programming approach:
``` swift
// 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")
```
Depending on which product you've picked, you'll have to import different modules:
```swift
// Pure Japx
import Japx
// Alamofire
import JapxAlamofire
// Alamofire and RxSwift
import JapxRxAlamofire
// Moya
import JapxMoya
// Moya and RxSwift
import JapxRxMoya
```
### Carthage
Run `carthage update --use-xcframeworks` and import desired integration. Pure `Japx` doesn't have any dependencies.
Imports work same as for Swift Package Manager, depending on which integration you've picked.
**NOTE: Moya integration is currently not supported via Carthage since latest Moya build won't build with Carthage. More info [here](https://github.com/Moya/Moya/issues/2165).**
## Example project
Example project of Japx networking using Codable and Alamofire can be found in [Nuts And Bolts repository][12] with commonly used code. [Example][13] will cover how to handle basic CRUD (Create, Read, Update, Delete) operations with Japx and JSON:API format. To run the example, clone the [repository][12], open the `Catalog.xcworkspace`, run Catalog app and navigate to the Japx Networking section.
In this repository there is also a simple example project, to run it open `Japx.xcodeproj` and inspect `Example` directory and Japx_Example scheme.
Basic integrations with Cocoapods (run `pod install`), Swift Package Manager and Carthage can be found inside `Examples` directory.
## Authors
* Vlaho Poluta, vlaho.poluta@infinum.hr
* Filip Gulan, filip.gulan@infinum.hr
Maintained by [Infinum][9]
## License
Japx is available under the MIT license. See the LICENSE file for more info.
[1]: http://jsonapi.org/
[2]: https://developer.apple.com/documentation/swift/codable
[3]: https://github.com/JohnSundell/Unbox
[4]: https://github.com/JohnSundell/Wrap
[5]: https://github.com/Hearst-DD/ObjectMapper
[6]: http://jsonapi.org/format
[7]: https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
[8]: http://cocoapods.org
[9]: https://infinum.co
[10]: https://github.com/Alamofire/Alamofire
[11]: https://github.com/ReactiveX/RxSwift
[12]: https://github.com/infinum/iOS-Nuts-And-Bolts
[13]: https://github.com/infinum/iOS-Nuts-And-Bolts/tree/master/Catalog/Examples/Networking/Japx