How To Serialize All AdonisJS Lucid Model Properties As Camel Case

In this lesson, we'll learn how to use Naming Strategies in AdonisJS to alter the serialization behavior for all our model properties from snake case to camel case.

Published
Jan 16, 22
Duration
6m 23s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

By default, AdonisJS will serialize model property names to snake_case. Meaning, if we send our model using JSON, or manually serialize the model, the property rememberMeToken would be converted to remember_me_token.

const user = await User.findOrFail(1)
const rememberMeToken = user.rememberMeToken // 👈 camelCase here

post.serialize() // 👈 then after serializing

/*
  {
    id: 1,
    remember_me_token: null // 👈 it'll change to snake_case
  }
*/

If we didn’t want this to happen, and instead have our property remain camelCased as rememberMeToken when serialized, we could manually add the serializeAs property on our model’s properties, but that can be time-consuming.

So, in this lesson, we’ll be taking a look at how to quickly and easily do this throughout all models using Naming Strategies.

Get An AdonisJS Project

If you’d like to follow along and need a project you can go ahead and clone down the repository from our AdonisJS Bouncer series. This project has auth, a couple of basic models, and CRUD for those models setup.

I’ll be cloning the project down as adonisjs-serializations.

git clone <https://github.com/jagr-co/adonisjs-bouncer.git> adonisjs-serializations

Install it’s dependencies, setup your environment variables by copying what is in .env.example and open it up in your text editor of choice and you’re ready to go!

Adding A Camel Case Strategy

Within your project, go ahead and create a new folder under app called Strategies, you can place this elsewhere if you’d like. Then, within your Strategies folder, create a new file called CamelCaseNamingStrategy.ts.

Within this file, we’ll want a default exported class that extends AdonisJS’ default SnakeCaseNamingStrategy, this is the strategy all models use by default.

// app/Strategies/CamelCaseNamingStrategy.ts

import { SnakeCaseNamingStrategy } from '@ioc:Adonis/Lucid/Orm'

export default class CamelCaseNamingStrategy extends SnakeCaseNamingStrategy {
}

Next, we’ll want to define how our strategy should serialize our model property names. For this, we can define a method called serializedName within our CamelCaseNamingStrategy.

// app/Strategies/CamelCaseNamingStrategy.ts

import { SnakeCaseNamingStrategy, BaseModel } from '@ioc:Adonis/Lucid/Orm'
import { string } from '@ioc:Adonis/Core/Helpers'

export default class CamelCaseNamingStrategy extends SnakeCaseNamingStrategy {
  public serializedName(_model: typeof BaseModel, propertyName: string) {
    return string.camelCase(propertyName)
  }
}

Here we’ve defined a public method called serializedName that accepts our model, of type BaseModel, and the property name it’s currently trying to serialize. The model argument name starts with an underscore because we won’t be using it. Then, inside the method all we need to do is mutate our property name however we wish and return the mutated name.

So, in our example, we’re using AdonisJS’ cameCase string helper to convert our property’s name to camel case.

There’s also a ton of other methods we can define using Naming Strategies to alter the default naming conventions for our models. For the full list, check out the Naming Strategy page of the documentation.

Applying Our Camel Case Strategy

Now that we have our strategy created, now we need to inform our model(s) to use it. We can do this by providing a new instance of our strategy’s class to the static namingStrategy property within our model’s class.

// app/Models/User.ts

// ... imports
import CamelCaseNamingStrategy from 'App/Strategies/CamelCaseNamingStrategy' // 👈 our strategy

export default class User extends BaseModel {
  // 👇 define a new instance of our strategy on the model
  public static namingStrategy = new CamelCaseNamingStrategy()
  
  @column({ isPrimary: true })
  public id: number

  @column()
  public roleId: number

  @column()
  public username: string

  @column()
  public email: string

  @column({ serializeAs: null })
  public password: string

  @column()
  public rememberMeToken?: string

  @column.dateTime({ autoCreate: true })
  public createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  public updatedAt: DateTime

  // ... other properties
}

With this, when we serialize our User model all the camel cased properties will now remain camelCase instead of the default snake_case.

const user = await User.findOrFail(1)
const rememberMeToken = user.rememberMeToken // 👈 camelCase here

post.serialize() // 👈 then after serializing

/*
  {
    id: 1,
    rememberMeToken: null // 👈 it'l now remain camelCase
  }
*/

Applying Naming Strategy To All Models

So, we now know how to do this on a per-model basis. We could go through and add this to each model, but what would be better is to have our own BaseModel that all our application’s models extend. This will allow us to define the naming strategy once. Plus, if we find ourselves in a similar situation in the future, all the prep work will be done and we’ll have a single spot, our BaseModel, that we need to alter.

Creating Our Base Model

To prevent naming conflicts, for our app’s BaseModel let’s use the name AppBaseModel or something of the sort. This will prevent issues with auto-import and the like pulling in the wrong import location.

So, let’s create a new file within our Models directory called AppBaseModel.ts. Then, inside this file, we’ll want a default exported class named AppBaseModel that extends AdonisJS’ BaseModel.

// app/Models/AppBaseModel.ts

import { BaseModel } from '@ioc:Adonis/Lucid/Orm'

export default class AppBaseModel extends BaseModel {
}

Then, we can apply our CamelCaseNamingStrategy directly to our AppBaseModel.

// app/Models/AppBaseModel.ts

import { BaseModel } from '@ioc:Adonis/Lucid/Orm'
import CamelCaseNamingStrategy from 'App/Strategies/CamelCaseNamingStrategy' // 👈 import it

export default class AppBaseModel extends BaseModel {
 public static namingStrategy = new CamelCaseNamingStrategy() // 👈 set as naming strategy
}

Using Our Base Model

Next, we’ll want to go through all our application’s models and swap our AdonisJS’ BaseModel with our AppBaseModel, like the below.

// app/Models/User.ts

// ... imports

// 👇 remove AdonisJS' BaseModel import
import { column, beforeSave, HasMany, hasMany } from '@ioc:Adonis/Lucid/Orm'

// 👇 import our AppBaseModel instead
import AppBaseModel from 'App/Models/AppBaseModel'

export default class User extends AppBaseModel { // 👈 update to AppBaseModel
  @column({ isPrimary: true })
  public id: number

  @column()
  public roleId: number

  @column()
  public username: string

  // ... other properties
}

Here we’ve removed the import for AdonisJS’ BaseModel from @ioc:Adonis/Lucid/Orm. Then, we imported our new AppBaseModel and swapped it out as the class our User models extends.

Do this for all models in your application, except your AppBaseModel, and you’ll be all set with your new CamelCaseNamingStrategy for all models. Plus, since you now have your own class all models extend, you have a singular place you can easily extend all your models for future changes.

Join The Discussion! (0 Comments)

Please sign in or sign up for free to join in on the dicussion.

robot comment bubble

Be the first to Comment!