Serialization

Serializers provide clean abstractions to transform database results.

AdonisJs ships with the default Vanilla Serializer, but you are free to create and use any serializer your application requires.

A common serializer usage is to format data as per the JSON:API spec.

Introduction

Database queries made via Lucid models return serializable instances:

const User = use('App/Models/User')

const users = await User.all()

// users -> Vanilla Serializer instance

To convert a serializable instance to a plain array/object, call its toJSON method:

const json = users.toJSON()

Calling toJSON on any serializable instance returns data ready for JSON output.

Why Use Serializers?

When writing an API server, it’s unlikely you’ll want to return unserialized model instance data to your users.

Serializers solve this problem by formatting model data when required.

Assuming a User can have many Post relations:

const User = use('App/Models/User')

const users = await User
  .query()
  .with('posts')
  .fetch()

In the example above, Lucid loads all User models and their Post relations, but doesn’t format the loaded data for JSON at this point in time.

When toJSON is finally called on users, the responsibility of formatting the data is delegated to the Vanilla Serializer:

// serialize the data
users.toJSON()
Output
[
  {
    id: 1,
    username: 'virk',
    posts: [
      {
        id: 1,
        user_id: 1,
        title: 'Adonis 101'
      }
    ]
  }
]

A serializer executes all getters, setters and computed properties before returning formatted model data.

Using Serializer

Serializers can be defined per model by overriding the Serializer getter:

app/Models/User.js
class User extends Model {
  static get Serializer () {
    return // your own implementation
  }
}

Vanilla Serializer

The Vanilla Serializer performs the following operations:

  1. Attach all relations next to each model record as a property.

  2. Attach all sideloaded data to the root __meta__ key, for example, posts counts for a given user are represented like so:

    {
      id: 1,
      username: 'virk',
      __meta__: {
        posts_count: 2
      }
    }
  3. Format pagination results:

    {
      total: 10,
      perPage: 20,
      lastPage: 1,
      currentPage: 1,
      data: []
    }

Creating Serializer

Create your own serializer to return data in a format not provided by AdonisJs.

The serializer API is intentionally small to make it easy to add new serializers.

Avoid custom serializers for small amends to JSON output. Instead, use getters and computed properties.

API Overview

Below is an example template for a custom serializer:

app/Serializers/CustomSerializer.js
class CustomSerializer {
  constructor (rows, pages = null, isOne = false) {
    this.rows = rows
    this.pages = pages
    this.isOne = isOne
  }

  first () {
    return this.rows[0]
  }

  last () {
    return this.rows[this.rows.length - 1]
  }

  size () {
    return this.isOne ? 1 : this.rows.length
  }

  toJSON () {
    // return formatted data
  }
}

module.exports = CustomSerializer

Once your custom serializer is created, bind it to the IoC container:

start/hooks.js
const { ioc } = require('@adonisjs/fold')

ioc.bind('MyApp/CustomSerializer', () => {
  return require('./app/Serializers/CustomSerializer')
})

Once bound to the container, define your custom serializer per model:

app/Models/User.js
class User extends Model {
  static get Serializer () {
    return 'MyApp/CustomSerializer'
  }
}