DEV Community

Cover image for NestJS CRUD with Postgres and TypeORM
Rohan Faiyaz Khan
Rohan Faiyaz Khan

Posted on • Originally published at rohanfaiyaz.com

NestJS CRUD with Postgres and TypeORM

Disclaimer: This was originally posted on my blog

NestJS is a fantastic framework for writing robust web backends. According to the docs:

Nest (or NestJS) is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with and fully supports TypeScript (yet still enables developers to code in pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming) Under the hood, Nest makes use of robust HTTP Server frameworks like Express (the default) and optionally can be configured to use Fastify as well!

Essentially Nest takes inspiration from enterprise level frameworks such as the .NET Framework while also offering the simplicity and flexibility of building a simple Node.js server with Express. Nest is inspired heavily from Angular and seeks to provide similar abstractions to the backend.

That's all fine and good, but why should you use Nest?

Well let me preface this by first saying that if have a preferred backend of choice in another language such as Django, Laravel or .NET, Nest won't offer any new tools or tricks. However if you have been building Node servers before you might have experienced the frustration of setting up the same application over and over again. Or you might have had difficulties maintaining the app as scale grew. Nest offers so many advantages over starting a project from scratch that I believe it will soon become a default for Node CRUD applications and APIs. Over this article I will try my best to show what those advantages are.

First of all there is TypeScript support and an application structure right out of the box. You don't have waste time setting up your application and straight away jump into creating your endpoints. In addition Nest comes with its own command line that lets scaffold the application and add components very quickly. Nest is also very platform agnostic and you can use any database or any frontend with it, For instance, it has TypeORM integration that can easily be set up with an MySQL, Postgres, SQL Server or even MongoDB database.

I will go through how to build a REST API capable of CRUD operations to demonstrate how easy it is to get started with Nest.

Get started with Nest

We will first install NestJS (if you don't already have it installed) using NPM and set up a new Nest project

$ npm i -g @nestjs/cli
$ nest new nest-app
Enter fullscreen mode Exit fullscreen mode

This will scaffold the application and ask you which package manager you prefer, npm or yarn. I used yarn for this example but feel free to use npm if you like. After installing we can test the server.

Installing Nest

We can test the installation by using yarn start. This will start the app by default on port 3000. We can navigate over to see a "Hello world" message.

Setting up Postgres

This part will assume you have Postgres installed. If not, install Postgres on OS, for instance you can use the official installer for Windows, use Homebrew on MacOS or apt on Ubuntu.

Once we have Postgres installed, we will want to create a database. We can do this using a GUI tool such as PGAdmin or simply using Postgres CLI. I am using Linux so I will use sudo to switch to the postgres user, which is the default superuser. We need the super user in order to call the the createdb command.

$ sudo -u postgres psql
postgres=# createdb rohan
postgres=# \q
Enter fullscreen mode Exit fullscreen mode

The command psql opens the Postgres CLI. \q quits the Postgres CLI. We can set a password to our local user so we can securely access the local database.

$ psql
rohan=# \password
rohan=# Enter new password:
rohan=# Retype new password
Enter fullscreen mode Exit fullscreen mode

Connecting our app to our Database

Firstly we will install the necessary dependencies. TypeORM is the suggested ORM and is very good for connecting with Postgres.

yarn add pg typeorm @nestjs/typeorm @nestjsx/crud
Enter fullscreen mode Exit fullscreen mode

Next we will create a config file at the root of our project and call it ormconfig.json.

{
    "type": "postgres",
    "host": "localhost",
    "port": 5432,
    "username": "rohan",
    "password": "password",
    "database": "rohan",
    "entities": ["dist/**/*.entity.js"],
    "synchronize": true,
    "logging": true
}
Enter fullscreen mode Exit fullscreen mode

Nest uses an application structure similar to Angular in the sense that there are controllers, modules and providers (or services) for each component. The root of the project contains an app.module and an app.controller. In order to include our TypeORM module, we must import in our app.module. Doing so makes the module available all over our application without needing to import it anywhere else. In the app.module.ts file inside the src directory, type:

import { Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import { TypeOrmModule } from '@nestjs/typeorm'
import { PokemonModule } from './pokemon/pokemon.module'

@Module({
    imports: [ TypeOrmModule.forRoot(), PokemonModule],
    controllers: [ AppController ],
    providers: [ AppService ]
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Don't worry about the Pokemon module, we will be creating it soon. You might notice here that the module is what connects the different parts of the component. We will include the TypeOrmModule's forRoot module with empty parameters. By default it will the configuration in our ormconfig.json as its parameters.

Creating an entity

Next let's create an entity. We will make an entity for pokemon! Make a new directory called pokemon and inside it create a file called pokemon.entity.ts.


import { Entity, Column, PrimaryGeneratedColumn} from 'typeorm'

@Entity('pokemon')
export class PokemonEntity {
    @PrimaryGeneratedColumn('uuid') id: string

    @Column('varchar', { length: 500, unique: true})
    name: string

    @Column('varchar', { length: 500 })
    type: string

    @Column('numeric')
    pokedex: number
}
Enter fullscreen mode Exit fullscreen mode

Setting up CRUD

Before setting up our CRUD operactions we have to import the entity created in our model. We can generate a model using the Nest CLI.

nest generate module pokemon
Enter fullscreen mode Exit fullscreen mode

This will auto generate a module for us called pokemon.module.ts.

import { Module } from '@nestjs/common'
import { PokemonService } from './pokemon.service'
import { PokemonController } from './pokemon.controller'
import { PokemonEntity } from './pokemon.entity'
import { TypeOrmModule } from '@nestjs/typeorm'

@Module({
    imports: [ TypeOrmModule.forFeature([ PokemonEntity ]) ],
    controllers: [ PokemonController ],
    providers: [ PokemonService ]
})
export class PokemonModule {}
Enter fullscreen mode Exit fullscreen mode

Next the service.

nest generate service pokemon
Enter fullscreen mode Exit fullscreen mode

Inside the newly created pokemon.service.ts file we will inject our CRUD service.

import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm'
import { PokemonEntity } from './pokemon.entity'

@Injectable()
export class PokemonService extends TypeOrmCrudService<PokemonEntity> {
    constructor (@InjectRepository(PokemonEntity) repo) {
        super(repo)
    }
}
Enter fullscreen mode Exit fullscreen mode

Finally in our pokemon controller we will set up our CRUD endpoints using the @nestjsx/crud package. This really demonstrates an area where NestJS shines. While it is possible to make all our endpoints manually (using @Get, @post, @Put, @Patch and @Delete decorators in our controller), the CRUD package allows us to set up all of this effortlessly in a few lines of code.

import { Controller} from '@nestjs/common'
import { Crud } from '@nestjsx/crud'
import { PokemonService } from './pokemon.service'
import { PokemonEntity } from './pokemon.entity'
@Crud({
    model: {
        type: PokemonEntity
    },
    params: {
        id: {
            field: 'id',
            type: 'uuid',
            primary: true
        }
    }
})
@Controller('pokemon')
export class PokemonController {
    constructor (public service: PokemonService) {}
}
Enter fullscreen mode Exit fullscreen mode

ANd with that CRUD automatically sets up the following endpoints:

  • GET /pokemon Get all
  • GET /pokemon/:id Get one by id
  • POST /pokemon Add one
  • POST /pokemon/bulk Add many
  • PUT /pokemon/:id Replace one
  • PATCH /pokemon/:id Update one

You can test out the new endpoints in Postman or curl.

That's it!

I don't know about you but when I first learned to make a REST API there was a lot more boilerplate code to figure out. Nest offers just the right amount of high level abstractions to make building APIs a fun process again because you will be focus on what really matters- the endpoints and the entities, Furthermore, NestJS's official docs has comprehensive recipes on integrating with GraphQL (a post on that coming soon) and others. If you are a NodeJS developer, NestJS is something very exciting to keep your eye on.

Oldest comments (1)

Collapse
 
nightwalkeryao profile image
Nightwalker Yao • Edited

The pg module is needed (npm i pg --save)
And had to manually import the ormconfig in app.module.ts
@Module({
imports: [ TypeOrmModule.forRoot(
require('../ormconfig.json')),
...
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}