node-dto

A small dto lib for nodejs

Usage no npm install needed!

<script type="module">
  import nodeDto from 'https://cdn.skypack.dev/node-dto';
</script>

README

Node Dto

CodeQL Node.js Package CircleCI Coverage Status

Node Dto is a small lib, that help developer to create dto's using javascript.

This package is focused only in javascript.

$ npm i node-dto

How use

The node-dto package exports MakeDto function, that is a factory to generate your custom Dto's.

The MakeDto function receive an array of object with this schema:

{
  name: String,
  serialize: String,
  type: 'Number' | 'String' | 'Date' | 'Boolean' | 'Enum' | 'Object' | 'Array',
  required: Boolean
}

Note: For type Number validator parses to Number Type in javascript check issue Add Number Parsing for Number type

Enum

For Enum type you need to pass a enumOps array props and specify, a list of accepted options.

Eg.

MakeDto([
  {
    name: 'opsStatus',
    serialize: 'ops_status',
    required: true,
    type: 'Enum',
    enumOps: ['pending', 'approved', 'rejected']
  }
]

Object

For Object type you need to pass a schema array of object props. The schema prop follow the same interface that MakeDto exports.

Eg-

MakeDto([
  {
    name: 'fields',
    serialize: 'fields',
    required: true,
    type: 'Object',
    schema: [
      {
        name: 'Name',
        serialize: 'name',
        required: true,
        type: 'Number',
      }
    ]
  }
]

Array

For Array type you need to pass a itemsType prop. The itemsType specify what will be type of array that will be validated.

In case of using Enum or Object you need to pass as well the enumOps or schema prop too.

Eg-

MakeDto([
  {
    name: 'fields',
    serialize: 'fields',
    required: true,
    type: 'Array',
    itemsType: 'Number'
  }
]

or

MakeDto([
  {
    name: 'fields',
    serialize: 'fields',
    required: true,
    type: 'Array',
    itemsType: 'Enum',
    enumOps: ['accepted', 'nullable']
  }
]

or

MakeDto([
  {
    name: 'fields',
    serialize: 'fields',
    required: true,
    type: 'Array',
    itemsType: 'Object',
    schema: [
      {
        name: 'StatusCode',
        serialize: 'status_code',
        required: true,
        type: 'Number'
      }
    ]
  }
]

Name

The name field is what key on object or array you will send. Eg. { fullName: 'Acidiney Dias' }

Serialize

The serialize field is the key the will be used to export after validate dto. Eg. { full_name: 'Acidiney Dias' }

Type

As name said, the type field tell to dto internal function how to validate this field.

This help us, to skip unecessary if statemenet to check types.

Note: If you pass an invalid type, you will receive an ValidateException.

Required

The required field, tell to dto internal function if can ignore when receive null in this field.

This prevents possible errors.

Eg. Receive an null on functions that calculate something.

Available Methods

.entries()

The entries() function returns all name keys wroted when Dto schema was created.

Eg:


// CreateUserDto.js

const { MakeDto } = require('node-dto')

module.exports = MakeDto([
  {
    name: 'firstName',
    serialize: 'first_name',
    required: true,
    type: 'String'
  },
  {
    name: 'lastName',
    serialize: 'last_name',
    required: true,
    type: 'String'
  },
  {
    name: 'email',
    serialize: 'email',
    required: true,
    type: 'String'
  }
])


// UserController.js

console.log(CreateUserDto.entries()) // firstName, lastName, email

You can use this, in request.only for example to retrive from request only this elements.

.validate(obj: Object | array)

The .validate function receive the current payload, validate with type and obrigatority and returns an serialized object or throws an ValidateException.

Eg.

Dto:


module.exports = MakeDto([
  {
    name: 'firstName',
    serialize: 'first_name',
    required: true,
    type: 'String'
  },
  {
    name: 'lastName',
    serialize: 'last_name',
    required: true,
    type: 'String'
  },
  {
    name: 'email',
    serialize: 'email',
    required: true,
    type: 'String'
  }
])

Comes:


CreateUserDto.validate({
  firstName: 'Acidiney',
  lastName: 'Dias',
  email: 'acidineydias@gmail.com'
})

Returns:


{
  first_name: 'Acidiney',
  last_name: 'Dias',
  email: 'acidineydias@gmail.com'
}

Or an exception when something is wrong:

Comes:


CreateUserDto.validate({
  firstName: 928292,
  lastName: 'Dias',
  email: 'acidineydias@gmail.com'
})

Returns:


ValidateException: Field firstName with value 928292, is not valid!

.export(data: Object | Array)

Sometimes you receive data from your database for exemple in one format like snake_case and you need tou transform to camelCase, in order to mantain your code more clean.

The .export function receives the untreated payload and returns a object using the fields name and serialize in your Dto.

Eg.


module.exports = MakeDto([
  {
    name: 'firstName',
    serialize: 'first_name',
    required: true,
    type: 'String'
  },
  {
    name: 'lastName',
    serialize: 'last_name',
    required: true,
    type: 'String'
  },
  {
    name: 'email',
    serialize: 'email',
    required: true,
    type: 'String'
  }
])

Comes:


CreateUserDto.export({
  first_name: 'Acidiney',
  last_name: 'Dias',
  email: 'acidineydias@gmail.com'
})

// or

CreateUserDto.export([
  {
  first_name: 'Acidiney',
  last_name: 'Dias',
  email: 'acidineydias@gmail.com'
},
{
  first_name: 'Jhon',
  last_name: 'Doe',
  email: 'jhon.doe@xyz.com'
}
])

Returns:

{
  firstName: 'Acidiney',
  lastName: 'Dias',
  email: 'acidineydias@gmail.com'
}

Or


[
  {
    firstName: 'Acidiney',
    lastName: 'Dias',
    email: 'acidineydias@gmail.com'
  },
  {
    firstName: 'Jhon',
    lastName: 'Doe',
    email: 'jhon.doe@xyz.com'
  }
]

.exportUsingSQL(entity = null)

Sometimes using .export function can be slower, if you are using too much data.

In this case, you can use .exportUsingSQL function that consider your Dto, and returns an Array of string.

You can use this array in the .select() function of your ORM.

Eg. Using Knex

  const users = await knex.from('users')
    .select(...Users.exportUsingSQL())
    .fetch();

Considering join's in queries you can pass the name of entity that this Dto belongs.

  const users = await knex.from('tokens')
    .select('tokens.token', ...Users.exportUsingSQL('users'))
    .innerJoin('users', 'tokens.user_id', 'users.id')
    .fetch();

Feel free to submit an PR, to help project.

Thanks ^^

Author

Acidiney Dias