Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,22 @@ const result = Serializer.serialize('article', data, 'default', {count: 2}, true

Some others examples are available in [tests folders](https://github.com/danivek/json-api-serializer/blob/master/test/)

#### Serialize a relationship endpoint

To serialize a [relationship endpoint](https://jsonapi.org/format/#fetching-relationships) (e.g. `GET /articles/1/relationships/tags`), use `serializeRelationshipData(type, data, [schema], [extraData])`. It returns a top-level document whose `data` contains [resource identifier objects](https://jsonapi.org/format/#document-resource-identifier-objects) only (`{ type, id }`), without `attributes` or nested `relationships`.

```javascript
Serializer.serializeRelationshipData('tag', [{ id: '2', name: 'foo' }, { id: '3', name: 'bar' }]);
// {
// "data": [
// { "type": "tag", "id": "2" },
// { "type": "tag", "id": "3" }
// ]
// }
```

`data` can be full resource objects (only the `id` is read) or bare ids, a single value or an array. Empty to-one relationships serialize to `null` and empty to-many relationships to `[]`.

### Deserialize

input data (can be an simple object or an array of objects)
Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ declare class JSONAPISerializer {
serialize(type: string | DynamicTypeOptions, data: any, schema?: string, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: { [type: string]: Partial<Options> }): any;
serializeAsync(type: string | DynamicTypeOptions, data: any, extraData?: any): Promise<any>;
serializeAsync(type: string | DynamicTypeOptions, data: any, schema?: string, extraData?: any, excludeData?: boolean, overrideSchemaOptions?: { [type: string]: Partial<Options> }): Promise<any>;
serializeRelationshipData(type: string | DynamicTypeOptions, data: any, schema?: string, extraData?: any): any;
deserialize(type: string | DynamicTypeOptions, data: any, schema?: string): any;
deserializeAsync(type: string | DynamicTypeOptions, data: any, schema?: string): Promise<any>;
serializeError(error: Error | Error[] | ErrorWithStatus | ErrorWithStatus[] | { [key: string]: any } | { [key: string]: any }[]): any;
Expand Down
20 changes: 20 additions & 0 deletions lib/JSONAPISerializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@
};
}

/**
* Serialize the linkage for a relationship endpoint (e.g. `GET /articles/1/relationships/tags`).
* Produces a top-level document whose `data` is resource identifier objects only
* (`{ type, id }`), without `attributes` or nested `relationships`.
* @see {@link https://jsonapi.org/format/#fetching-relationships}
* @see {@link https://jsonapi.org/format/#document-resource-identifier-objects}
* @function JSONAPISerializer#serializeRelationshipData
* @param {string|Function} type the related resource's type.
* @param {object|object[]|string|string[]} data related resource(s) or their id(s).
* @param {string} [schema='default'] the related resource's schema name.

Check warning on line 135 in lib/JSONAPISerializer.js

View workflow job for this annotation

GitHub Actions / build (20.x)

Defaults are not permitted on @param

Check warning on line 135 in lib/JSONAPISerializer.js

View workflow job for this annotation

GitHub Actions / build (18.x)

Defaults are not permitted on @param

Check warning on line 135 in lib/JSONAPISerializer.js

View workflow job for this annotation

GitHub Actions / build (16.x)

Defaults are not permitted on @param
* @param {object} [extraData] additional data passed to type-resolving functions.
* @returns {object} a top-level document with linkage-only `data`.
*/
serializeRelationshipData(type, data, schema = 'default', extraData = {}) {
// Discard included: a relationship endpoint returns linkage only, not related resources.
return {
data: this.serializeRelationship(type, schema, data, new Map(), undefined, extraData),
};
}

/**
* Asynchronously serialize input data to a JSON API compliant response.
* Input data can be a simple object or an array of objects.
Expand Down
47 changes: 47 additions & 0 deletions test/unit/JSONAPISerializer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,53 @@ describe('JSONAPISerializer', function() {
});
});

describe('serializeRelationshipData', function() {
const Serializer = new JSONAPISerializer();
Serializer.register('tag', {});

it('should serialize to-many linkage as resource identifier objects only', function(done) {
const tags = [{id: '2', name: 'foo'}, {id: '3', name: 'bar'}];

const serializedData = Serializer.serializeRelationshipData('tag', tags);

expect(serializedData.data).to.be.instanceof(Array).to.have.length(2);
expect(serializedData.data[0]).to.eql({type: 'tag', id: '2'});
expect(serializedData.data[1]).to.eql({type: 'tag', id: '3'});
expect(serializedData.data[0]).to.not.have.property('attributes');
expect(serializedData.included).to.be.undefined;
done();
});

it('should serialize to-one linkage as a single resource identifier object', function(done) {
const serializedData = Serializer.serializeRelationshipData('tag', {id: '2', name: 'foo'});

expect(serializedData.data).to.eql({type: 'tag', id: '2'});
expect(serializedData.data).to.not.have.property('attributes');
expect(serializedData.included).to.be.undefined;
done();
});

it('should serialize linkage from bare ids', function(done) {
const serializedData = Serializer.serializeRelationshipData('tag', ['2', '3']);

expect(serializedData.data[0]).to.eql({type: 'tag', id: '2'});
expect(serializedData.data[1]).to.eql({type: 'tag', id: '3'});
done();
});

it('should serialize empty to-many linkage as an empty array', function(done) {
const serializedData = Serializer.serializeRelationshipData('tag', []);
expect(serializedData.data).to.eql([]);
done();
});

it('should serialize empty to-one linkage as null', function(done) {
const serializedData = Serializer.serializeRelationshipData('tag', null);
expect(serializedData.data).to.eql(null);
done();
});
});

describe('serializeAsync', function() {
const Serializer = new JSONAPISerializer();
const dataArray = [{
Expand Down
Loading