logo
Skip to Main Content

Overview

The Serializer class is used to describe which attributes and relationships to include for a particular resource.

The attributes and relationships you declare in a Serializer will determine the attributes and relationships that will be included in the response from the resource that the Serializer represents.

Attributes

You can add attributes to your serializer using an array assigned to the class property attributes like the example below.

class UsersSerializer extends Serializer {
  attributes = [
    'name',
    'email',
    'username',
    'createdAt',
    'updatedAt'
  ];
}

Since the attributes required for a resource are declared ahead of time in a Serializer, Lux will optimize SQL queries for the resource to only include what the Serializer needs to build the response.

import { Serializer } from 'lux-framework';

class PostsSerializer extends Serializer {
  attributes = [
    'body',
    'title',
    'createdAt'
  ];
}

export default PostsSerializer;

The Serializer above would result in resources returned from the /posts endpoint to only include the body, title, and createdAt attributes. If we wanted include an additional attribute such as isPublic, we would have to add 'isPublic' to the attributes property.

import { Serializer } from 'lux-framework';

class PostsSerializer extends Serializer {
  attributes = [
    'body',
    'title',
    'isPublic',
    'createdAt'
  ];
}

export default PostsSerializer;

Associations

Similar to attributes you can declare associations by adding relationship names to either the hasOne or hasMany property arrays on a Serializer.

Serializers are not concerned with ownership when it comes to associations, so both hasOne and belongsTo associations can be specified in the hasOne array property.

import { Model } from 'lux-framework';

class Post extends Model {
 static hasOne = {
   image: {
     inverse: 'post'
   }
 };

 static hasMany = {
   tags: {
     inverse: 'posts',
     through: 'categorization'
   },

   comments: {
     inverse: 'post'
   }
 };

 static belongsTo = {
   user: {
     inverse: 'posts'
   }
 };
}

export default Post;

To include the user and image associations in the response returned from the /posts endpoint, we must specify both associations in the hasOne property array of the Serializer.

import { Serializer } from 'lux-framework';

class PostsSerializer extends Serializer {
 hasOne = [
   'user',
   'image'
 ];
}

export default PostsSerializer;

If we wanted to also include the tags and comments in the response, we have to add a hasMany array property containing 'tags' and 'comments'.

import { Serializer } from 'lux-framework';

class PostsSerializer extends Serializer {
 hasOne = [
   'user',
   'image'
 ];

 hasMany = [
   'tags',
   'comments'
 ];
}

export default PostsSerializer;

You no longer need to specify that tags is a many to many relationship using the Categorization model as a join table.

When requesting related resources for an endpoint, the included resource will follow the serialization rules defined by the included resources Serializer.

If we request that the posts association is included from the /users endpoint, we will only get the attributes that the PostsSerializer has defined even though the response is processed by the UsersSerializer.

Sparse Fieldsets

When a request specifies the fields that it would like included in the response, the fields MUST be declared in the attributes property array of the resources Serializer, or they will be ignored.

Namespaces

When using namespaces, you are not required to have a Serializer for each resource as long as a Serializer for the given resource can be resolved upstream.

For example, if you have a posts resource and you decide to implement an admin namespace, you only need to export an AdminPostsSerializer from app/serializers/admin/posts.js if you want to specify different attributes or relationships than the PostsSerializer exported from app/serializers/posts.js.

In the event that you do want to specify different attributes or relationships that the PostsSerializer exported from app/serializers/posts.js, you are not required to extend PostsSerializer.

import { Serializer } from 'lux-framework';

class PostsSerializer extends Serializer {
  attributes = [
    'body',
    'title',
    'createdAt'
  ];

  hasOne = [
    'user',
    'image'
  ];

  hasMany = [
    'tags',
    'comments'
  ];
}

export default PostsSerializer;

To add the isPublic attribute to the response payload of requests to a /admin/posts endpoint we can do either of the following examples:

// app/serializers/admin/posts.js
import PostsSerializer from 'app/serializers/posts';

class AdminPostsSerializer extends PostsSerializer {
  attributes = [
    'body',
    'title',
    'isPublic',
    'createdAt'
  ];
}

export default AdminPostsSerializer;

OR

// app/serializers/admin/posts.js
import { Serializer } from 'lux-framework';

class AdminPostsSerializer extends Serializer {
  attributes = [
    'body',
    'title',
    'isPublic',
    'createdAt'
  ];

  hasOne = [
    'user',
    'image'
  ];

  hasMany = [
    'tags',
    'comments'
  ];
}

export default AdminPostsSerializer;

Even with inheritance, the examples above are a tad repetitive. We can improve this code by exporting constants from app/serializers/posts.js.

import { Serializer } from 'lux-framework';

export const HAS_ONE = [
  'user',
  'image'
];

export const HAS_MANY = [
  'tags',
  'comments'
];

export const ATTRIBUTES = [
  'body',
  'title',
  'createdAt'
];

class PostsSerializer extends Serializer {
  hasOne = HAS_ONE;
  hasMany = HAS_MANY;
  attributes = ATTRIBUTES;
}

export default PostsSerializer;

If we choose to use inheritance, our code can look like this:

// app/serializers/admin/posts.js
import PostsSerializer, { ATTRIBUTES } from 'app/serializers/posts';

class AdminPostsSerializer extends PostsSerializer {
  attributes = [
    ...ATTRIBUTES,
    'isPublic'
  ];
}

export default AdminPostsSerializer;

If we choose not use inheritance, our code can look like this:

// app/serializers/admin/posts.js
import { Serializer } from 'lux-framework';
import { HAS_ONE, HAS_MANY, ATTRIBUTES } from 'app/serializers/posts';

class AdminPostsSerializer extends PostsSerializer {
  hasOne = HAS_ONE;
  hasMany = HAS_MANY;

  attributes = [
    ...ATTRIBUTES,
    'isPublic'
  ];
}

export default AdminPostsSerializer;

Properties

  • Source:src/packages/serializer/index.js:378

    An array of the attributes on a Serializer instance's Model to include in the attributes resource object of a serialized payload.

    class PostsSerializer extends Serializer {
      attributes = [
        'body',
        'title'
      ];
    }
    
  • Source:src/packages/serializer/index.js:359

    An Array of the hasMany relationships on a Serializer instance's Model to include in the relationships resource object of a serialized payload.

    class PostsSerializer extends Serializer {
      hasMany = [
        'comments'
      ];
    }
    
  • Source:src/packages/serializer/index.js:339

    An Array of the hasOne or belongsTo relationships on a Serializer instance's Model to include in the relationships resource object of a serialized payload.

    class PostsSerializer extends Serializer {
      hasOne = [
        'user'
      ];
    }