jsonapi-serializer
jsonapi-serializer copied to clipboard
transforming not possible for relationships
I'm using the transform callback with success when setting up a serializer attribute. However, when I pass the same option to the relationship, it just isn't called.
const PersonSerializer = new Serializer('persons', {
attributes: ['id', 'name', 'isAlive', 'relatives'],
transform: (person) => {
person.isAlive = !person.deadAt
return person
},
// works
relatives: {
attributes: ['id', 'name', 'isAlive'],
transform: (person) => {
person.isAlive = !person.deadAt
return person
},
// doesn't work
}
this might be because the feature doesn't exist, but I'd say it should, according to the principle of least surprise.
Also, I can't seem to pass a serializer to a relationship (using the example above, having a RelativeSerializer and somehow passing it to serialize the relationship). Is this actually possible or in the roadmap?
I solved this problem in our app by recursing down both the data and the serialization config in the main transform via the following function.
/**
* Transform this level and recurse into all attributes that have
* nested models and transform there as well
*/
export function transformRecursively(model, record) {
// Only Transform on objects not arrays of objects
if (Array.isArray(record)) {
return record.forEach(rec => transformRecursively(model, rec));
}
//Act
if (model && model.transform && typeof model.transform === 'function' && record) {
model.transform(record);
}
//Recurse on attributes that have model objects
if (record && model && model.attributes) {
model.attributes.forEach((key) => {
if (model[key]) {
transformRecursively(model[key], record[key]);
}
})
}
}
And then in the main transform calling it via:
// Run transformations recursively on any sub-modules that have a transform function
this.attributes.forEach((key) => {
transformRecursively(this[key], record[key]);
});
Its been working out for us thus far but your mileage might vary.
@SeyZ are you open to PRs for this? I ran into this as well. I think it'd make a nice addition to an already great package.
As I discovered while looking into the same issue, you can transform relationships by just digging deeper into the primary resource's properties. To use the example above:
const PersonSerializer = new Serializer('persons', {
attributes: ['id', 'name', 'isAlive', 'relatives'],
transform: (person) => {
// transform primary
person.isAlive = !person.deadAt
// transform relationship
const relatives = person.relatives
relatives = relatives.map(relative => {
relative.person.isAlive = !relatives.person.deadAt
return relative
})
// return primary
return person
},
relatives: {
attributes: ['id', 'name', 'isAlive'],
}
}