Japx is lightweight JSON:API parser that flattens complex JSON:API structure and turns it into simple JSON and vice versa.
This example will cover how to handle basic CRUD (Create, Read, Update, Delete) operations with Japx and JSON:API format.
Struct definition that API requires is given with PokedexUser.
struct PokedexUser: JapxCodable {
let id: String
let type: String = "users"
let email: String?
let username: String?
let password: String?
let passwordConfirmation: String?
let authToken: String?
}
PokedexUser conforms to JapxCodable protocol which is typealias for JapxDecodable and JapxEncodable. This is just extension of Codable protocol with additional required properties type
and id
.
Encoding this model with JapxEncoder will transform it into [String: Any] dictionary which is then encoded with JSONEncoder to convert it into JSON. JSON example for updating users email and username:
{
"data": {
"id": "80",
"type": "users",
"attributes": {
"email": "[email protected]",
"username": "username-79"
},
"relationships": {}
}
}
PokedexRouter class defines information required to send successful requests to the API. There are 4 different router functions (for each operation). Example of the router usage for updating user properties:
static func updateUser(id: String, email: String?, username: String?) -> PokedexRouter {
let pokedexUser = PokedexUser(id: id, email: email, username: username)
let params = try? JapxEncoder().encode(pokedexUser)
let encodableParam = EncodableParams(encoding: JSONEncoding.default, parameters: params)
return PokedexRouter(
baseUrl: "https://pokeapi.infinum.co/api/v1",
path: "/users/\(id)",
method: .put,
encodableParams: [encodableParam]
)
}
Base API service
class is used for communicating with API. It contains function requestJSONAPI
which sends request, validates given response and returns result of your Decodable object through completion.
func requestJSONAPI<T: Decodable>(
_: T.Type,
includeList: String? = nil,
keyPath: String? = nil,
decoder: JapxDecoder = JapxDecoder(jsonDecoder: .init()),
router: Routable,
session: Session,
completion: @escaping (AFResult<T>) -> ()
) -> DataRequest {
return sessionManager
.request(router)
.validate()
.responseCodableJSONAPI(
includeList: includeList,
keyPath: keyPath,
decoder: decoder,
completionHandler: { completion($0.result) }
)
}
}
If keypath is specified with "data" (root of JSON:API format) then you can simply pass on your model, in this case PokedexUser
, as a generic Decodable. Otherwise use JapxResponse
which has your model in the data property.
func updateUser(
id: String,
email: String?,
username: String?,
completion: @escaping (AFResult<PokedexUser>) -> Void
) -> DataRequest {
let router = PokedexRouter.updateUser(id: id, email: email, username: username)
return service
.requestJSONAPI(
PokedexUser.self,
keyPath: "data",
router: router,
session: session,
completion: completion
)
}
public struct JapxResponse<T: Codable>: Codable {
public let data: T
}