diff --git a/README.md b/README.md index 37781d5..4b7d04e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Serializer.register(type, options); * **meta** (optional): Describes meta that contains non-standard meta-information about the relationship. It can be: * An _object_ (values can be string or function). * A _function_ with one argument `function(data) { ... }` or with two arguments `function(data, extraData) { ... }` + * **deserialize** (optional): Describes the function which should be used to deserialize a related property which is not included in the JSON:API document. It should be: + * A _function_ with one argument `function(data) { ... }`which defines the format to which a relation should be deserialized. By default, the ID of the related object is returned, which would be equal to `function(data) {return data.id}`. See [issue #65](https://github.com/danivek/json-api-serializer/issues/65). * **convertCase** (optional): Case conversion for serializing data. Value can be : `kebab-case`, `snake_case`, `camelCase` **Deserialization options:** diff --git a/lib/JSONAPISerializer.js b/lib/JSONAPISerializer.js index afcf2b6..0fb4566 100644 --- a/lib/JSONAPISerializer.js +++ b/lib/JSONAPISerializer.js @@ -61,6 +61,7 @@ module.exports = class JSONAPISerializer { schema: joi.string().default('default'), links: joi.alternatives([joi.func(), joi.object()]).default({}), meta: joi.alternatives([joi.func(), joi.object()]).default({}), + deserialize: joi.func(), })).default({}), topLevelLinks: joi.alternatives([joi.func(), joi.object()]).default({}), topLevelMeta: joi.alternatives([joi.func(), joi.object()]).default({}), @@ -487,13 +488,19 @@ module.exports = class JSONAPISerializer { if (resourceOpts.relationships[relationshipKey] && resourceOpts.relationships[relationshipKey].alternativeKey) { relationshipKey = resourceOpts.relationships[relationshipKey].alternativeKey; } + const deserializeFunction = (relationshipData) => { + if (resourceOpts.relationships[relationshipKey] && resourceOpts.relationships[relationshipProperty].deserialize) { + return resourceOpts.relationships[relationshipProperty].deserialize(relationshipData); + } + return relationshipData.id; + }; if (relationship.data !== undefined) { if (Array.isArray(relationship.data)) { // Array data _set(deserializedData, relationshipKey, relationship.data.map(d => (included ? this.deserializeIncluded(d.type, d.id, resourceOpts.relationships[relationshipProperty], included) - : d.id))); + : deserializeFunction(d)))); } else if (relationship.data === null) { // null data _set(deserializedData, relationshipKey, null); @@ -501,7 +508,7 @@ module.exports = class JSONAPISerializer { // Object data _set(deserializedData, relationshipKey, included ? this.deserializeIncluded(relationship.data.type, relationship.data.id, resourceOpts.relationships[relationshipProperty], included) - : relationship.data.id); + : deserializeFunction(relationship.data)); } } }); diff --git a/test/unit/JSONAPISerializer.test.js b/test/unit/JSONAPISerializer.test.js index f807dfc..4dffb2f 100644 --- a/test/unit/JSONAPISerializer.test.js +++ b/test/unit/JSONAPISerializer.test.js @@ -1520,6 +1520,43 @@ describe('JSONAPISerializer', function() { done(); }); + it('should deserialize with \'deserialize\' option as a function', function(done) { + const Serializer = new JSONAPISerializer(); + Serializer.register('articles', { + relationships: { + author: { + type: 'people', + deserialize: (data) => ({id: data.id, type: data.type}) + } + } + }); + + const data = { + data: { + type: 'article', + id: '1', + attributes: { + title: 'JSON API paints my bikeshed!', + body: 'The shortest article. Ever.', + created: '2015-05-22T14:56:29.000Z' + }, + relationships: { + author: { + data: { + type: 'people', + id: '1' + } + } + } + } + }; + + const deserializedData = Serializer.deserialize('articles', data); + expect(deserializedData.author).to.have.property('id'); + expect(deserializedData.author).to.have.property('type'); + done(); + }) + it('should deserialize with \'unconvertCase\' options', function(done) { const Serializer = new JSONAPISerializer(); Serializer.register('articles', {