Framework-agnostic JSON:API Serializer
json-api-serializer is a versatile JavaScript library for Node.js and browsers, designed to serialize JavaScript objects into JSON:API 1.0 compliant documents and deserialize JSON:API documents back into standard JavaScript objects. The current stable version is 2.6.6. It maintains an active development cycle, frequently releasing minor updates and bug fixes. Key differentiators include its framework-agnostic nature, extensive configuration options for defining complex relationships, links, and metadata, and support for both serialization and deserialization processes. It allows for fine-grained control over attribute whitelisting/blacklisting, case conversion, and custom logic for handling relationships, making it adaptable to various JSON:API implementations.
Common errors
-
RangeError: Maximum call stack size exceeded
cause Circular references in the data being serialized or deserialized, leading to an infinite recursion.fixRefactor your data to break circular dependencies, or ensure you are using `json-api-serializer` version 2.4.1 or higher which includes fixes for preventing circular deserialization. -
Error: Relationship '...' is not registered.
cause Attempting to serialize or deserialize data that contains a relationship to a type ('...') which has not been registered with the `serializer.register()` method.fixRegister all resource types involved in relationships using `serializer.register('type', options)` before performing any serialization or deserialization operations that involve those relationships. -
TypeError: Cannot read properties of undefined (reading 'id')
cause This error can occur during deserialization when an unregistered relationship is encountered, or when a relationship's `deserialize` function attempts to access `data.id` on an `undefined` or malformed relationship object.fixEnsure all relationships are properly registered. Review the `deserialize` function for relationships in your `serializer.register()` options to handle cases where `data` might be `null` or `undefined`, especially for optional relationships. Upgrade to `v2.6.5` or higher which fixes errors when deserializing unregistered relationships.
Warnings
- breaking Older versions (prior to 2.4.1) could enter an infinite loop when deserializing data with circular references, leading to a 'Maximum call stack size exceeded' error.
- gotcha Attempting to serialize or deserialize a relationship for a type that has not been explicitly registered with `serializer.register()` will lead to errors.
- gotcha Deserialized data might have `undefined` `id` fields if the input JSON:API document lacks an `id` for a resource, which can cause issues if your application expects all resources to have an `id`.
- deprecated The behavior regarding the `included` array in serialized output has been adjusted. Previously, the `included` array might have been present even if the input had no attributes. This is now fixed to be more compliant.
Install
-
npm install json-api-serializer -
yarn add json-api-serializer -
pnpm add json-api-serializer
Imports
- JSONAPISerializer
const JSONAPISerializer = require('json-api-serializer');import JSONAPISerializer from 'json-api-serializer';
- Serializer (instance)
import { Serializer } from 'json-api-serializer';import JSONAPISerializer from 'json-api-serializer'; const serializer = new JSONAPISerializer();
Quickstart
import JSONAPISerializer from 'json-api-serializer';
// 1. Initialize the serializer
const serializer = new JSONAPISerializer();
// 2. Register a 'user' type
serializer.register('user', {
id: 'uuid', // Use 'uuid' as the ID field instead of default 'id'
blacklist: ['passwordHash'],
relationships: {
posts: {
type: 'post', // The type of the related resource
links: {
self: (data, extraData) => `/users/${data.uuid}/relationships/posts`
}
},
comments: {
type: 'comment',
alternativeKey: 'commentIds' // Use 'commentIds' if 'comments' relationship key is missing
}
},
links: {
self: (data) => `/users/${data.uuid}`
}
});
// 3. Register a 'post' type
serializer.register('post', {
attributes: ['title', 'content', 'createdAt'],
relationships: {
author: {
type: 'user',
deserialize: (data) => data.id // Custom deserialization for author
}
}
});
// Example Data
const userData = {
uuid: 'u123',
name: 'Alice',
email: 'alice@example.com',
passwordHash: 'hashedpassword',
posts: [{ id: 'p1', title: 'My First Post' }, { id: 'p2', title: 'Another Post' }],
commentIds: ['c1', 'c2']
};
const postData = {
id: 'p1',
title: 'My First Post',
content: 'Hello World!',
createdAt: new Date().toISOString(),
author: { id: 'u123' }
};
// 4. Serialize data
const serializedUser = serializer.serialize('user', userData);
console.log('Serialized User:', JSON.stringify(serializedUser, null, 2));
// 5. Deserialize data (requires a full JSON:API document)
const jsonApiDoc = {
data: {
type: 'user',
id: 'u123',
attributes: {
name: 'Alice',
email: 'alice@example.com'
},
relationships: {
posts: {
data: [
{ type: 'post', id: 'p1' },
{ type: 'post', id: 'p2' }
]
}
}
},
included: [
{ type: 'post', id: 'p1', attributes: { title: 'First Post Title' } },
{ type: 'post', id: 'p2', attributes: { title: 'Second Post Title' } }
]
};
const deserializedData = serializer.deserialize('user', jsonApiDoc);
console.log('Deserialized Data:', JSON.stringify(deserializedData, null, 2));