NestJS — build CRUD web services in minutes

Most software systems have areas with complicated business logic, usually, the core of the system is where this code lives. On the other hand, some features that simply need to store/retrieve data and do not require complex solutions at all. More than often, the core of the system is augmented with simple CRUD (create, read, update, and delete) operations. And, as some CRUD actions do not require custom logic, they can, and in my opinion, should be autogenerated.

Besides the obvious benefit of saving on development time, other benefits that should not be overlooked. To name a few:

  • Fewer bugs
  • Consistency out of the box (naming, features, etc.)
  • Requires minimum testing
  • Usually, you get docs for free

Now that we have addressed when and why to use autogenerated CURD APIs, let’s explore how can we do it with the nestjs.

We are going to build a simple RESTful API for product management.

The following examples do not require any previous knowledge of nestjs.

How to do it?

Make sure you have the NestJS CLI installed:

npm i -g @nestjs/cli

Or, if you don’t like to add dependencies to your global node_modules you can always use npx. Anyway, once you have it installed you have to decide on the project name. I will call mine nestjs-crud.

nest new nestjs-crud

Once the project is created simply navigate to the project folder (in this case it will be cd nestjs-crud) and type:

npm run start

By default, the nestjs projects start on the port 3000. If open to the mentioned port in your browser you should see the following:

Running nestjs

Now that we have the basic project up and running we can move the next section.

Install nestjs/crud dependencies

As CRUD utilities are not part of the core nestjs framework, we need to install the following dependencies.

npm i @nestjsx/crud @nestjsx/crud-typeorm @nestjs/typeorm typeorm class-transformer class-validator

Generate skeleton

Generate the skeleton by executing the following command:

nest generate module product && \
nest generate controller product && \
nest generate service product && \
nest generate class product/product

At the time of writing this the generator doesn’t produce much output, it gives files with just a few lines of code in it. However, besides generating files, it does some plumbing work for us. Check out the image below, lines starting with CREATE , obviously, are new generated files and UPDATED are the plumbing step I mentioned.

Nestjs cli generator

Putting it all together

The building block of a nestjs application, such as models, services, controllers, and modules won’t be discussed in detail in this post. You can read more about it here.

Model

The first step is to define our model (commonly referred to as entity). The above command didn’t do much, the content of the product.ts file is the following:

export class Product {}

What we need to do now is to add a few properties which define our product model.

Product model — Source code

Service

The next component we need to adjust is product.service.ts. This is the place “magic” actually happens.

So, replace the:

import { Injectable } from '@nestjs/common';@Injectable()
export class ProductService {}

With:

Product service — Source code

Controller

In the product.controller.ts, we need to attach the @Crud decorator to wire everything together.

Product Controller — Source code

Input validation

Adding input validation to our service is really easy with the help of class-validator library we installed in one of the previous steps. All we have to do is to attach the desired decorators to the target properties. For example:

Product model with input validation — Source code

Database config

For the sake of keeping things simple I decided to go with sql.js as it doesn’t require running an external service. All we have to do is install the sql.js:

npm i sql.js

And, in the project root, create the ormconfig.json file and paste the following code:

{
"type": "sqljs",
"entities": [
"dist/product/product.js",
],
"synchronize": true
}

To inject the database connection to our services we need to change two different modules files. The first one is product.module.ts. All we have to do is add the line number 6.

Product module — Source code

The other file we need change is the app.module.ts. Again, we have to modify the imports property of the @Module decorator by adding TypeOrmModule.forRoot() to the array.

App module — Source code

If everything is done correctly you should be able to run the app:

npm run build && npm start

and see the following

Running the product service

Here are a few cURL examples to help you with testing the endpoint:

Get all products:

curl -X GET "http://localhost:3000/product" -H "accept: application/json"

Create a product

curl -X POST "http://localhost:3000/product" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\":\"my product\",\"sku\":\"mysku\",\"price\":10}"

Autogenerated docs

As the nestjs have a supports Open API (swagger) adding documentation to our project is simple. Install swagger dependencies:

npm install @nestjs/swagger swagger-ui-express

To enable docs all we have to do is to modify the bootstrap function (src/main.ts) to include swagger config.

Adding docs to nestjs app — Source code

Now, if we navigate to the http://localhost:3000/docs you should get the docs.

Conclusion

In conclusion, the nestjs framework and especially the @nestjs/crud give us a really rich set of functionality out of the box. Regardless if you are familiar or not with the nestjs framework, it is surprisingly quick to setup and get your first CRUD service. One feature I hope to see in the future of this project is the ability to replicate all the above steps via a single CLI command, a similar way it’s done by .NET and rails.

You can find the full source code on Github.

Software engineer based in Stockholm, Sweden.