Skip to main content

3. Creating Entities

Introduction to the Entity concept

Entities are the natural place for abstractions from your domain. Usually, big things like User, Order, Contract Agreement, Shopping Cart, Schedule, etc. are entities.

Entities have properties (fields), actions (methods) and often is uniquely identified by an ID.

Refer to Getting Started - What's and Entity to know more.

For this project, the most basic entity is the User. The CLI generates it out-of-the-box, so let's understand how it works:

Generated User Entity

First, let's understand how entity code works:

// Path: src/domain/entities/user.js

/*
First, import from herbsjs package the main functions
to create a entity, define entity fields and make
entity avaible for application.
*/
const { entity, id, field } = require('@herbsjs/herbs')
const { herbarium } = require('@herbsjs/herbarium')


/*
Here we start a const called User, thats receives
from entity() function a instance of Entity that will
represent an User.

The entity() function expects two arguments,
in this sintax entity(entity_name, entity_body).

- First argument entity_name is a string thats determines this Entity name
- Second argument entity_body is a object with properties
thats represents Entity attributes
*/
const User = entity('User', {
// The key of this object defines a field name.
// The value is the object type of determined by `field()` function.

// `id()` is a special field to define a entity unique identifier.
id: id(Number),

// Both the fields "nickname" and "password" are texts, therefore we are using `String`.
nickname: field(String),
password: field(String)
})

/*
Finally we are exporting our entity, but we don't do
this direct like `module.exports = User`.

herbsjs works with automagic dependecy injection, so to do
magic works we will need use a herbarium to export our entities
and make it avaible for all application.

It's only necessary pass to module.export, herbarium.entities.add().entity,
passing by add() as first argument our entity object, in this case is User,
and as second argument a string with a name of entity 'User'.
*/
module.exports =
herbarium.entities
.add(User, 'User')
.entity

Entity fields

In the User entity, we has seen the fields:

  • id: The unique identifier for the user.
  • nickname: The nickname for the user like "user123".
  • password: The user's access password.

But within the entity fields properties, we can do more, is possible set a default value for a field or make some validation, for now, is important know the type of field are Scalar types, tere are some of them:

  • Number: double-precision 64-bit binary format IEEE 754 value
  • String: a UTF‐16 character sequence
  • Boolean: true or false
  • Date: represents a single moment in time in a platform-independent format.

List Entity

For our TODO api we need 2 entities, List and Item, first let's creates a list. for this entity let's reuse a User Entity previous auto generated by herbs-cli

  1. Rename de file from user.js to list.js src/domain/entities/user.js -> src/domain/entities/list.js

  2. Inside a file let's rename User to List

    From this

    const User = entity('User', {  ...

    To this

    const List = entity('List', {  ...
  3. Rename in exports to

    From this:

    module.exports =
    herbarium.entities
    .add(User, 'User')
    .entity

    To this:

    module.exports =
    herbarium.entities
    .add(List, 'List')
    .entity
  4. Finaly, let's update fields for List Entity

    From this:

    {     
    id: id(Number),
    nickname: field(String),
    password: field(String)
    }

    To this:

    {     
    id: id(Number),
    name: field(String),
    description: field(String)
    }

Now our List entity code will looks like:

const { entity, id, field } = require('@herbsjs/herbs')
const { herbarium } = require('@herbsjs/herbarium')

const List = entity('List', {
id: id(Number),
name: field(String),
description: field(String)
})

module.exports =
herbarium.entities
.add(List, 'List')
.entity

and as a final touch, delete user folder inside src/domain/usecases/, because we will run the herbs update command that will create the uses cases for our new entity, besides of repository and migration files that we will deal with in the next steps.

Item Entity

Let's create a new entity Item

  1. create a file item.js inside folder src/domain/entities/

  2. very similar with List lets create our Item entity code:

    //start a file importing dependencies:
    const { entity, id, field } = require('@herbsjs/herbs')
    const { herbarium } = require('@herbsjs/herbarium')

    /*
    create a const Item and assign a entity()
    passing all arguments needed with fields for the item
    */
    const Item = entity('Item', {
    id: id(Number),
    name: field(String),
    completed: field(Boolean)
    })

    // finally exports Item entity
    module.exports =
    herbarium.entities
    .add(Item, 'Item')
    .entity

  3. again after create a entity let's run the herbs update command and keep things up to date.

Entity fields default value

When CLI generate code to us, we have a just a base, but we can go further.

Just for example, imagine that Item entity as a task, so when we created it, the field completed must be false, because we don't do task yet.

To make this happen, we can set a default value for field completed, we just need adapt our entity creating code to:

// src/domain/entities/item.js
const Item = entity('Item', {
id: id(Number),
name: field(String),
completed: field(Boolean, {
default: false
})
})

Learn more about default values.

Entity fields validation

Once we have the fields set, other important thing to do is implement validation to them. For example, when we create a List, we need indentify there, so we will set a name, but to prevents thats some user try save a list whitout a name we can set a validation to field name, thats make field be required.

The validation is passed as an Object and it can have different kinds of parameters, such as presence, length and numericality. For example:

In our List entity will set some validations in field id to make it required, just accept integer values an must be greater than 0 and field name to be required and have a minimum of three letters.

// src/domain/entities/List.js
...
const List = entity('List', {
id: id(Number, {
validation: {
// The field MUST be present
presence: true,
numericality: {
// Must be greater than 0
greaterThan: 0,
// Cannot be a float
onlyInteger: true
}
}
}),
name: field(String, {
validation: {
// The field MUST be present
presence: true,
// Here, the name MUST have 3 letters at least
length: { minimum: 3 },
}
}),
description: field(String)
})

Learn more about validations with Herbs.


Feel free to implement more fields and add different kinds of validation to it.

Now that we have the List and Item entities, let's move on to setting up a database, where we will save our Lists and Items.