A fast, simple JSON serializer for your Sequelize models. Turns model instances into plain JSON-friendly objects that can be safely embedded in API responses. Suitable for serializing large numbers of instances at once.
Serialization can be performed according to named schemes, of which any number can be defined for a model. A scheme specifies the properties to be be included or excluded in the result, and can also provide schemes to use for associated models.
Should work with both Sequelize 3.x and 4.x. Examples provided in this document are based on Sequelize 3. See here for the list of changes introduced in the new major release of Sequelize.
Proper test suite is the next thing on the roadmap. Until it comes into existence the package shoud not be considered stable.
sequelize-to-json
requires Node 4.4.x or later.
Install it within your project's tree using NPM:
npm install --save sequelize-to-json
The module doesn't install any dependiences. It just ships with a custom minimized lodash
build (to be removed in future releases).
A nice walkthrough has yet to be written. For now, just a crude example.
Assuming we already have a working Sequelize instance providing us with User
and BlogPost
models and at least the author
relation:
const
Serializer = require('sequelize-to-json'),
db = require('./db'), // our Sequelize instance, with models and relations already defined
BlogPost = db.model('BlogPost'),
User = db.model('User');
// our serialization scheme for the `BlogPost` model with the associated `User` (stored in the `author` field)
const scheme = {
// include all own properties and the associated `User` instance
include: ['@all', 'author'],
// let's exclude from the above the primary key and all foreign keys
exclude: ['@pk', '@fk'],
assoc: {
// scheme to be used for the associated `User` instance
author: {
// include just a selection of fields (URLs are method calls but they could be implemented as VIRTUAL attributes as well)
include: ['fullName', 'aboutMe', 'getProfileUrl', 'getAvatarUrl'],
// let's assign better names to properties obtained via instance methods
as: { getProfileUrl: 'profileUrl', getAvatarUrl: 'avatarUrl' }
}
}
};
// now fetch some posts, with authors, and serialize them
BlogPost.findAll({
include: { model: User, as: 'author' },
// ...
}).then(function(posts) {
// serialize all the items efficiently
let postsAsJSON = Serializer.serializeMany(posts, BlogPost, scheme);
// serialize just the first item
let serializer = new Serializer(BlogPost, scheme);
let postAsJSON = serializer.serialize(posts[0]);
// ...
});
Resulting JSONified post objects would look like this (assuming BlogPost
contains the title
and content
fields):
{
"title": ...,
"content": ...,
...,
"author": {
"fullName": ...,
"aboutMe": ...,
"profileUrl": ...,
"avatarUrl": ...
}
}
See the Reference below for the complete description of sequelize-to-json
features.
Represents a serializer.
Serializer objects can process any number of instances of a given model using the specified scheme. Both the model class and the scheme are tied to a serializer object; you'll need to instantiate a new serializer for each model / scheme pair.
This class is the only thing exported by the module. It can be accessed directly by requiring sequelize-to-json
.
(The class doesn't actually have a name of it's own; i'm using here the name Serializer
just for clarity. You can import it under any name you wish.)
Creates a new serializer.
Arguments are:
model
- Sequelize model class whose instances are to be serializedscheme
- scheme to be used for serialization. Can be an object, a string or anything falsy.options
- object containing additional options (see Options)
If scheme
is a string, the scheme definition will be searched for in model.serializer.schemes
. If scheme
is falsy, following steps will be performed to identify the serialization scheme:
- If
model.serializer.defaultScheme
is set, it will be interpreted as the name of scheme to use (frommodel.serializer.schemes
). - If there's no
model.serializer.defaultScheme
, the scheme is checked for inmodel.serializer.schemes.default
. - If there's no scheme named
default
inmodel.serializer.schemes
, the global default scheme is used (see below).
For info on defining schemes, see the schemes section.
Serializes a single model instance into a JSON-friendly object, according to the scheme provided in constructor.
instance
must be an instance of the proper model class, otherwise the method will throw an error.
cacheObj
should only be used if the serialize
method is to be called repeatedly, eg. when processing a collection of model instances. In such cases, the cacheObj
argument should be a reference to an existing plain object, which will serve as a cache for storing Serializer
instances created recursively to process associated model instances.
For example:
let serializer = new Serializer(SomeModel, someScheme);
let cache = {}, json = [];
for(let item of items) {
json.push(serializer.serialize(item, cache));
}
Without passing cache
in the .serialize
call (or with cache
being set inline to {}
!) the performance will drop significantly since Serializer
objects will have to be re-created for each item.
Convenience static method for serializing collections of model instances. It uses the Serializer
object cache internally so that serializers are not re-created for associated model instances. See #serialize()
for details.
The model
, scheme
and options
parameters are passed to the Serializer
constructor.
Converts regular Javascript objects into JSON-friendly format. This function is used by default for the conversion of values returned by Sequelize.
obj
is the object (value) to be encoded. options
can be used to fine-tune the encoder.
Currently supported options:
bufferEncoding
- how to encode binaryBuffer
contents into a string. The value gets passed to Node'sBuffer#toString()
. Default:base64
Notes on how values are converted:
- Strings, booleans, numbers and nulls are copied as is
- Arrays and objects are processed recursively
- Dates are stringified using
#toString()
- Buffers are stringified using
#toString()
with encoding specified in options
Object holding the global defaults for serialization options.
Scheme are defined as plain objects. They can contain following fields:
include
- a list of attributes to be included in resulting objects. Defaults to all attributes (['@all']
). See Attribute lists for details.exclude
- a list of attributes to be excluded from the result. Filtering is applied to the attribute list defined byinclude
. Defaults to an empty list. See Attribute lists for details.assoc
- an object containing schemes for associated model instances. Object's keys should correspond to names of attributes holding related instances (Sequelize'sas
). Values can be either scheme names or scheme objects. They will be passed to theSerializer
constructor when creating serializers for associated instances.as
- can be used to rename attributes in output. Should be an object mapping model attribute names to names we would like to have in JSON. Useful for naming properties obtained from method calls (eg. to havepostExcerpt
instead ofgetPostExcerpt
).options
- serializer options. They will override options passed to theSerializer
constructor.postSerialize
- the hook function to be called after the instance has been converted into object. It receives the output object as the first argument and the original instance as the second one. Must return the (modified) output object. Gets called after the model-widepostSerialize
hook.
Both the include
and the exclude
fields of a scheme definition should contain a list of model's attributes. But, these lists can be a little more than just plain arrays of attribute names. They can also contain:
- method names (to be called with no arguments),
- regular instance properties,
@
-prefixed selectors that expand to subsets of model attributes sharing certain features.
Attributes can be prefixed with a dot to mark them expicitely as regular attributes of the model instance object.
sequelize-to-json
provides support for following attribute selectors:
@all
- all attributes defined for the model@assoc
- all associations in the model@pk
- the primary key (if present)@fk
- all foreign keys@doc
- all document-type fields:JSON
,JSONB
,HSTORE
@blob
- allBLOB
s@virtual
- allVIRTUAL
attributes@auto
- all attributes auto-generated by Sequelize (eg.created_at
,updated_at
...)
Note: model attribute values are obtained by calling .get()
on the model instance. This means custom getters get executed.
In order to keep things clean, serialization schemes can be kept inside models. This is done by adding a static serializer
property to the model class. You can either set this property directly or just put it in classMethods
when defining the model.
Supported serializer
fields are:
schemes
- an object containing available serialization schemes (keys are names and values are scheme objects)defaultScheme
- name of the default scheme for this model. The name should exist as a proper key inschemes
.options
- model-wide defaults for serialization optionspostSerialize
- the model-wide hook function to be called after the instance has been converted into object. It gets called with the serialization scheme asthis
and receives 3 arguments: the output object, the original model instance and the name of the serialization scheme. Must return the (modified) output object. Gets called before the scheme-specificpostSerialize
hook.
Following options can be used to tune the serialization output:
encoder
- a function used to convert JS types to JSON-friendly format. It should accept an object to be encoded and can be also passed options. Default:Serializer.encodeToJSON()
undefinedPolicy
- what to do with attributes that areundefined
for the instance. Allowed policies areSerializer.SKIP
(exclude from output),Serializer.SET_NULL
(set their values tonull
) andSerializer.FAIL
(throw an error). Default:Serializer.SKIP
copyJSONFields
- whether values stored as JSON (JSON
,JSONB
etc.) should be copied directly without passing them throughencoder
. Having it on will improve performance a bit. Default:true
simpleDates
- whetherDATEONLY
fields should be encoded inYYYY-MM-DD
format with the timezone offset applied. If set tofalse
, they will be stringified as full date-times. Default:true
. Note: In Sequelize 4DATEONLY
fields are implemented as strings model-side so this option will have no effect.encoderOptions
- options to be passed toencoder
(as the second argument)attrFilter
- function to filter model attributes before serialization. Can be useful in certain cases, eg. when one wants to get rid of duplicates of auto-generated attributes (such assome_id
showing up together withsomeId
). The function gets passed 2 arguments: the attribute object and the model object. It should returnfalse
for the attribute to be excluded from serialization.
Above options can be customized in four different places altogether (with precedence from the top to the bottom):
- in constructor (passed as the last argument);
- inside a scheme object;
- inside a model;
- globally, by modifying
Serializer.defaultOptions
.
To save yourself some typing and require
ing across the application code, you can add serialization methods globally to all your models. Just use define.classMethods
and define.instanceMethods
options during Sequelize instantiation:
const db = new Sequelize(..., {
//...
define: {
classMethods: {
serializeMany: function(data, scheme, options) {
return Serializer.serializeMany(data, this, scheme, options);
},
//...
},
instanceMethods: {
serialize: function(scheme, options) {
return (new Serializer(this.Model, scheme, options)).serialize(this);
},
//...
}
},
//...
});
Now you can use these methods like so:
// for single object
let json = myModelInstance.serialize('someScheme');
// for many objects
let json = MyModel.serializeMany(instances, 'someScheme');
Of course you can provide the scheme as an object and pass serializer options as the last argument for both methods.