Comments (18)
In the JSON API specification, on “relationships object”, we have the following:
null for empty to-one relationships.
an empty array ([]) for empty to-many relationships.
See http://jsonapi.org/format/#document-resource-object-linkage for more info.
In my opinion, I think it's better to avoid adding this option, because the outputed data will not be JSON API compliant. And the role of a serializer is to prevent generating non-compliant response.
@Mattii any thoughts ?
from json-api-serializer.
Yes, I think JSON API compliance should be our goal here. @karellm, could you explain why you don't want to have the data-field included?
from json-api-serializer.
I'm not familiar with the entire spec and I agree that it is a good idea to follow it. Maybe I'm missing something.
I use Ember.js, and if a relationship as data: []
or data: null
, then it removes all the items already associated. That is to be expected. I actually think that it is the proper behaviour.
Ember also relies on links
to know how to grab the data. So it is important to include these, otherwise, Ember doesn't know how to get the "school students".
In an application (think optimization), I might want to fetch only the school from the database, without bothering with the students. In that scenario, I would like the serialized payload to include the links
to the students so it knows where to grab them if needed but ignore the data
altogether. I would skip the attribute. I can't have it be []
or null
since it would clear the potentially existing relations in my Ember app. That said, Ember wouldn't do anything if the data
attribute is not there.
Does it clarify a bit the use case I'm hitting? Does the spec say anything about skipping the data
attribute? I understand the valid values but that's not my concern here. It is really its presence.
from json-api-serializer.
Yes, that's a valid use-case. Could you show us the complete source object, that you pass to the serializer?
I have a similar use-case and if I don't define the relationship in my source-object, the relationship will only contain the links
field (like you need it).
from json-api-serializer.
I use sequelize so I have little control over the source object. Here is what I can tell you (assuming a school with 1 student):
const school = await School.findById(1);
school.students // function
school.students() // []
Now if I include students:
const school = await School.findById(1, {include: [Student]});
school.students // [{id: 1, name: 'John'}]
I don't know if that helps. What I can say is that this would greatly help us in our current application. It allows for some neat optimizations of the db queries.
from json-api-serializer.
I think that if the relation students
is on of null
, { ... }
or [ ... ]
it could be included (even if these are empty). Otherwise it could be skipped (undefined
, string
, function
).
It could either be a default behaviour (I think it is a fair one) or an option skipDataIfMissing
.
from json-api-serializer.
What do you pass to the serializer? The school
object? How does it look?
Maybe it's best if you post the complete code from fetching the database to serializing the response.
If you don't want the students
relationship's data-field to be set, then the students
field in school
needs to be undefined
.
from json-api-serializer.
@Mattii The result of JSON.stringify(school)
in my first example (without the include) doesn't have a students
key at all, so yes it would be undefined
:
const school = await School.findById(1);
JSON.stringify(school);
{
"id": "1",
"name": "School Name"
}
const school = await School.findById(1, {include: [Student]});
JSON.stringify(school);
{
"id": "1",
"name": "School Name",
"students": [
{ "id": 1, "name": "John" }
]
}
I'm not familiar with the internal of Sequelize or json-api-serializer so I'm not sure what object you rely one. If you need more informations, let me know.
from json-api-serializer.
@karellm, I'm not familiar with Ember or Sequelize, but if I correctly understand, you are facing the issue only on your first example, without include, right ?
If so it should be undefined
. If not, can you post the result of typeof school.students
on your first example ?
from json-api-serializer.
@karellm I think you are trying to serialize the Sequelize model instance instead of a JSON object. I take a look at the Sequelize doc, and I think you will have better result with calling toJSON()
before passing it to the serializer.
from json-api-serializer.
I will summarize everything. But I think I mislead the conversation bringing Sequelize and Ember into the mix. In short if the students
is undefined (first example below), I'd like a way to avoid data
to be set on the relationship.
Without include
const school = await School.findById(1)
typeof school.students // function
school.students() // []
school.toJSON()
{
"id": "1",
"name": "School Name"
}
Currently serialized as:
{
data: {
id: 1,
type: 'schools',
attributes: {
name: 'some school'
},
relationships: {
data: null,
links: { /*...*/ }
}
}
}
Expected serialized content:
{
data: {
id: 1,
type: 'schools',
attributes: {
name: 'some school'
},
relationships: {
// no data!
links: { /*...*/ }
}
}
}
With include
const school = await School.findById(1, {include: [Student]})
typeof school.students // object
school.students // [{ "id": 1, "name": "John" }]
school.toJSON()
{
"id": "1",
"name": "School Name",
"students": [
{ "id": 1, "name": "John" }
]
}
Current (and expected) serialized content:
{
data: {
id: 1,
type: 'schools',
attributes: {
name: 'some school'
},
relationships: {
data: [
{
id: 1,
type: 'students'
}
],
links: { /*...*/ }
}
}
}
from json-api-serializer.
I made a simple try with version 1.7.0
const JSONAPISerializer = require('json-api-serializer');
const Serializer = new JSONAPISerializer();
// Schools type
Serializer.register('schools', {
relationships: {
students: {
type: 'students',
links: {
self: '/students'
}
}
}
});
// Students type
Serializer.register('students');
// Input data for schools
const input = {
"id": "1",
"name": "School Name"
};
const output = Serializer.serialize('schools', input);
console.log(JSON.stringify(output, null, 2));
output is:
{
"jsonapi": {
"version": "1.0"
},
"data": {
"type": "schools",
"id": "1",
"attributes": {
"name": "School Name"
},
"relationships": {
"students": {
"links": {
"self": "/students"
}
}
}
}
}
from json-api-serializer.
I definitely don't get the same results. I actually get:
Running exactly the code you pasted, I get the same result. That's really weird, a similar setup in my project (even passing an object like the input
you shared) returns data: undefined
.
UPDATE: I'm trying to isolate what part of my config triggers this issue. At the moment even super simple serializer still include the data: undefined
.
from json-api-serializer.
Maybe I repeat myself but I think you try to serialize Sequelize model instance. Try this:
const input = school.toJSON();
Serializer.serialize('schools', input);
or to be sure (bad practice):
const input = JSON.parse(JSON.stringify(school));
Serializer.serialize('schools', input);
from json-api-serializer.
@danivek Ok so actually JSON.stringify
strips the undefined values. Try to run this:
const JSONAPISerializer = require('json-api-serializer');
const Serializer = new JSONAPISerializer();
// Schools type
Serializer.register('schools', {
relationships: {
students: {
type: 'students',
links: {
self: '/students'
}
}
}
});
// Students type
Serializer.register('students');
// Input data for schools
const input = {
"id": "1",
"name": "School Name"
};
const output = Serializer.serialize('schools', input);
console.log(output.data.relationships.students);
I get:
{ links: { self: '/students' }, data: undefined }
This undefined
is my issue. I can also confirm that whether my output is school
or school.toJSON()
doesn't change anything.
from json-api-serializer.
@karellm Yes, and Ember has a different behavior between undefined
and missing property ?
from json-api-serializer.
Your problem seems not to be related to json-api-serializer, but to the way your server formats its responses. I recommend to use JSON.stringify
for every response, since it produces a valid JSON-string and removes undefined
values of an object:
> console.log(JSON.stringify({ links: { self: '/students' }, data: undefined }, null, 2))
{
"links": {
"self": "/students"
}
}
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
from json-api-serializer.
@danivek @Mattii Thanks for the great help here. I will definitely introduce JSON.stringify
.
from json-api-serializer.
Related Issues (20)
- ObjectID (mongodb) should be serialized with .toString() and not treated as an object HOT 2
- Support extracting error class names into the 'title' field of JSON API errors HOT 1
- Error when try to deserialise an included relationship with `alternativeKey` HOT 3
- ErrorMaximum call stack size exceeded if `included` has cross references
- Would you be interested in a conversion to Typescript? HOT 2
- Error instance serialization missing properties HOT 1
- ValidationError: beforeSerialize is not allowed HOT 2
- Incorrectly deserializing relationship when alternativeKey is set from default and relationship data is not in the included array HOT 2
- Case conversion breaks on non-alphanumeric strings
- Unintended object in attributes HOT 2
- Is there an option to remove undefined properties? HOT 1
- The result after serialize will not have `included` if the input doesn't have attributes HOT 5
- Error thrown when relationship is not registered HOT 5
- Having no attributes in the relation data does not add relation to included array
- Use a cache for converting to snake/camel/kebab case HOT 1
- bug: When installed in Angular project, it throws error since it is searching for `fs` HOT 3
- Relationships do not work with ES2015 classes
- bug: Duplicated models from includes are removed from response HOT 1
- Support serialization of only meta HOT 2
- Support for relationship data serialization? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from json-api-serializer.