devour-client
devour-client copied to clipboard
Defining models and attributes
// Define Model
jsonApi.define('post', {
title: '',
content: '',
tags: []
})
@Emerson why is this step necessary? I'm unable to find any reference to the models and attributes being used in the codebase. Are there roadmap features that will make use of this? Is it useful on the client?
This may well be possible and a better approach – but I'd like to think through the logic a little more just to be sure.
The real heavy lifting that this library does is around serializing
and deserializing
objects according to the JSON API spec. As it stands, the ability to declare a model also gives us:
- Ability to define custom URLs (no longer needed with the new URL builder pattern)
- An easy way to use your own custom serializer
- The ability to declare
readOnly
attributes (we wouldn't need this if we got rid of model definitions) - The ability to explicitly map relationships to object properties
My main concern is around relationships and flexibility. You can see here exactly what the spec calls for – and it seems like we would have enough information to just do this on the fly.
This response:
{
"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"
}
}
]
}
Would just be deserialized into:
{
"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": {
{
"id": "42",
"name": "John",
"age": 80,
"gender": "male"
}
}
}
On second thought, I think the main concern is around providing Devour users with an easy way to override some of the internals of the request/response cycle on a per model basis. Without a model definitions, we fallback to "Just add a custom middleware" or find a way to make it work in your own app. In my mind, we (at least) need to provide an easy way to:
- override serialization for a specific model
- override deserialization for a specific model
Maybe this is something that we could optionally pass into our calls?
let options = {
serializer: ()=> {
/* ... */
},
deserializer: ()=> {
/* ... */
}
}
devour.one('user', 1).get(params, options)
^ Using this pattern gives us the ease of ad-hoc modeless usage, but also provides users a mechanism to override core functionality and create a sort-of "model" if they need to.
Perhaps, we should just make it model optional? If you want to use a model and get the best of the best, great, if you just want to use the library as a URL builder, fine as well?
We'd need to rewrite a good deal of the serialization logic – but I'm open to any of it.
I think you need this decode library, what I doing to solve this problem is replace the response middleware with a customer middle, like this:
// response handler middleware
const responseMiddleware = {
name: 'deserialize-response-middleware',
res: (payload) => {
console.log('=====json api middleware payload=====', payload)
let jsonApi = payload.jsonApi
let status = payload.res.status
let req = payload.req
let res = payload.res.data
let included = res.included
if (status !== 204 && needsDeserialization(req.method)) {
store.sync(res)
return store
}
// 0 => no need to deserializer
return 0
}
}
// request headers
const headers = auth.getAuthHeader()
client.headers = headers
client.replaceMiddleware('response', responseMiddleware)
and then... you can call the serializered collection or resource in the promise :)
hope helps...