Saving time when starting a project
Published: 2021-10-11 12:30:54

![clock on the plate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ndgfvxujtqsah1641ju0.jpg)

## How much time do you spend setting up the basis of a new project?

No matter how simple or complex is your service, we have to build the base, that basic base: 
- Create entities
- Create the folder structure
- Then create some repositories
- Some usecases/services for each entity
- Configure the api, routes, midlewares
- etc

Come oooooooonnnn, who likes to do this?

## How to save time configuring the base's project?

Today we will create a Postgres-based api with two presentation layers: Graphql and REST in less then 1 minute.

For today's dish, we use the ingredients: 
- [@herbs/herbs](https://herbsjs.org/docs/) 
- [Herbs CLI](https://github.com/herbsjs/herbs-cli)

To start our "fast project" we need first of all to modeling our base. Imagine we are creating an e-commerce backend app, in an e-commerce we would have 3 entities: **user**, **product** and **sale**.

 ![black boy thinking](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pta9uiq58tocdm26ww91.png)

The first step to build our project will be to create the entities using the @herbs/herbs lib that will provide some metadata to build everything else based in our entities: usecases, repositories, migrations, graphql, rest etc.

Building an entity with Herbs is very simple, just import the `entity` module and pass the parameters `entity("entityName", { fields })`.

All our entities will be inside a folder `/entities`

``` js
// entities/customer.js
const { entity, field } = require('@herbsjs/herbs')


const Customer = entity('Customer', {
    id: field(Number),
    cellphone: field(String),
    email: field(String),
    gender: field(String),
    age: field(Number),
    discountClub: field(Boolean),
    city: field(String),
    state: field(String),
    address: field(String),
    zipcode: field(String),
    lastName: field(String),
    fisrtName: field(String),
    civilDocument: field(String),
})

module.exports = Customer
```

After create our simple entity, what about add some validations? To do this with Herbs is very simple too, just add an option object with some rules as second parameter `field(Type, { options })`.

If you'd like to see more about validation types, you can check out the Herbs documentation [here](https://herbsjs.org/docs/entity/validation/).


``` js
// entities/customer.js
const { entity, field } = require('@herbsjs/herbs')

const requiredString = {
    validation: {
        presence: true,
        length: { minimum: 3, maximum: 255 },
    }
}

const Customer = entity('Customer', {
    id: field(Number, {
        // Optional option
        validation: {
            presence: true,
            numericality: {
                greaterThan: 0,
                onlyInteger: true
            }
        }
    }),
    cellphone: field(String, {
        validation: {
            format: /^\+[1-9]{1}[0-9]{3,14}$/
        }
    }),
    email: field(String, {
        validation: { ...requiredString.validation, email: true } 
    }),
    gender: field(String, {
        validation: { ...requiredString.validation, contains: { allowed: ["M", "W", "X"] } } 
    }),
    age: field(Number),
    discountClub: field(Boolean),
    city: field(String, requiredString),
    state: field(String, requiredString),
    address: field(String, requiredString),
    zipcode: field(String, requiredString),
    lastName: field(String, requiredString),
    fisrtName: field(String, requiredString),
    civilDocument: field(String, requiredString),
})

module.exports = Customer
```

``` js
// entities/product.js
const { entity, field } = require('@herbsjs/herbs')

const required =  { validation: { presence: true } }
const requiredString = {
    validation: {
        ...required.validation,
        length: { minimum: 3, maximum: 255 },
    }
}

module.exports = entity('Product', {
    id: field(Number, {
        // Optional option
        validation: {
            presence: true,
            numericality: {
                greaterThan: 0,
                onlyInteger: true
            }
        }
    }),
    limitDiscount: field(Number, { 
        validation: { 
            greaterThan: 0,
            lessThan: 100,
            onlyInteger: true 
        }
    }),
    size:  field(String, required),
    stock: field(Number, required),
    color: field(String, required),
    name: field(String, requiredString),
    brand: field(String, requiredString),
    category: field(String, requiredString),
    description: field(String, requiredString),
    price: field(Number, { validation: { presence: true, greaterThan: 0 } }),
})
```
``` js
// entities/sale.js
const { entity, field } = require('@herbsjs/herbs')

const required =  { validation: { presence: true } }

module.exports = entity('Sale', {
    id: field(Number, {
        // Optional option
        validation: {
            presence: true,
            numericality: {
                greaterThan: 0,
                onlyInteger: true
            }
        }
    }),
    productID: field(Number, required),
    customerID: field(Number, required),
    total: field(Number, required),
    quantity: field(Number, required)
})
```

In the end we will have this result:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2b3rur4fva927rk2b8c0.png)

## generating the project

Finally our dreamed come to be true, where we generated our project based on our entities!

![amazing jack](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mwpi3yo1yay5l414hyoo.gif)

The Herbs CLI was created to help you create and maintain your project in a faster way when you uses the entire Herbs ecosystem.

When we type `herbs new` herbs will ask a some things about your project to generate our project.

![cli options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxx0ibveg0sjaxpy2mhq.png)

Note the last question is an **optional** question, if you don't specify your entities folder path, the project will be generated based on a default “User” entity, but we're not here to generate a “boilerplate” are we? So let's fill it in with out entities folder path.

When you press Enter our app will be generated and you will find a folder with the project name.

![Generated folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7erhmuab9sa7ser0nwdv.png)

look this! How much automatically generated stuff! How much time we saved here! Very satisfying! Note that the entire project is done: migrations, repositories, api(graphl and rest) create, read, update and delete usecases and everything else!

![wow gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p10sophlm5c9o52iteua.gif)

## Explaining the project

Okay, but what we built here? 

The diagram below shows a little bit how the project is organized (which you can check on the Herbs [doc home](https://herbsjs.org)), the generated app is based on the clean architecture, there we have our `domain` with our `entities` and our `usecases`, around from this we have the rest of our application (api, database, clients, documentation, etc.) and in all these other layers use the herbsjs "glues" that read the entities and usecases metadatas to facilitate our day-a-day software development, `remembering that no glue is a code generator`, are just tools to speed up the development of your code.

![Herbs archtecture ecosystem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yy67ynm7klnwo5111ien.png)

now let's be a little practical and talk about the our project's folder structure.

NOTE: remembering that architecture is not a folder structure!

![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0l57zols7j71t18bma3.png)

Inside `domain` folder we have our entities and usecases that provide some metadata as usecase's name, request and output schema, entity fields, types and more.

Above we have herbs2gql glue example, the [herbs2gql](https://herbsjs.org/docs/glues/herbs2gql) receive a usecase and a resolver so it return the Graphql schemas string. 

![Glue example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wq8mu86lqgdlqycohd00.png)

The concept of “glue” runs throughout the application, from the presentation layer to the repository, remembering it isn't mandatory and this libraries are only meant to help you develop and maintain your project. :)

Inside our usecases we can see that exists not anly a simples creation, but there have a validations too, so it means the generated project is done to production! 

## Running the project

Once we've generated and understood the code, let's put this code to work! Just give the `npm run start` command and watch the magic happen. Note that all REST routes are printed on the terminal and that they are all based on our usecases.

![REST terminal routes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57l28r175zho75b0ep0u.png)

Also, if you open your browser on the `http://localhost:3000/graphql` route you will see all generated schemas for the Graphql presentation layer with the Graphql playground documentation

![graphql playground](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzfd9p9f98bfsa07fhg8.png)

Beside everything we generated here, the herbs generates a dynamic documentation too, so imagine you'll never need to worry about your API's documentation since everything will be automatically generated via usecase metadata and your Readme.md file! To do that we use the [HerbsShelf](https://herbsjs.org/docs/glues/herbsshelf) glue

![Herbsshlef](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmahdqukp9fszjbx2cho.png)

So now just implement your business rule and go up to production!

![The end gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cgn9rrixd8lh0mfq53z3.gif)