CRUD app with NestJs using TypeORM

A basic CRUD app using NestJs

1. Create project

npm i -g @nestjs/cli
nest new tasks-api
npm run start:dev

2. Overview and delete files

3. Create module

nest g mo tasks
nest g s tasks/services/tasks
nest g s tasks/services/tasks --flat
nest g co tasks/controllers/tasks --flat

4. Check endpoint and create CRUD

import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';

@Controller('api/tasks')
export class TasksControllerController {

  @Get()
  findAll() {
    return [1,2,3];
  }

  @Get(':id')
  findOne(@Param('id') id: number) {
    return id;
  }

  @Post()
  create(@Body() body: any) {
    return body;
  }

  @Put(':id')
  update(@Param('id') id: number, @Body() body: any) {
    return body;
  }

  @Delete(':id')
  delete(@Param('id') id: number) {
    return true;
  }

}

5. Intall DB (Docker)

version: '3.3'

services:
  postgres:
    image: postgres:13
    environment:
      - POSTGRES_DB=my_db
      - POSTGRES_USER=nico
      - POSTGRES_PASSWORD=postgres
    ports:
      - '5432:5432'
    volumes:
      - ./postgres_data:/var/lib/postgresql

https://dev.to/andrewallison/docker-and-windows-1cb0

6. Add .gitignore /postgres_data

docker-compose up -d postgres
docker-compose exec postgres bash
psql -h localhost -d my_db -U nico
\d+
\q

7. Intall TypeOrm

npm install --save @nestjs/typeorm typeorm pg

8. App Module

TypeOrmModule.forRoot({
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'nico',
  password: 'postgres',
  database: 'my_db',
  entities: ['dist/**/*.entity{.ts,.js}'],
  synchronize: false,
  retryDelay: 3000,
  retryAttempts: 10
}),

9. Task Entity

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

@Entity()
export class Task {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column({ default: false })
  completed: boolean;
}

10. Tasks Module

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Task } from './entities/task.entity';
import { TasksService } from './services/tasks.service';
import { TasksController } from './controllers/tasks.controller';

@Module({
  imports: [
    TypeOrmModule.forFeature([Task])
  ],
  providers: [TasksService],
  controllers: [TasksController]
})
export class TasksModule {}

11 Service

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Task } from './../entities/task.entity';

@Injectable()
export class TasksService {

  constructor(
    @InjectRepository(Task) private tasksRepo: Repository<Task>,
  ) {}

  findAll() {
    return this.tasksRepo.find();
  }

  findOne(id: number) {
    return this.tasksRepo.findOne(id);
  }

  create(body: any) {
    const newTask = new Task();
    newTask.name = body.name;
    // const newTask = this.tasksRepo.create(body);
    return this.tasksRepo.save(newTask);
  }

  async update(id: number, body: any) {
    const task = await this.tasksRepo.findOne(id);
    this.tasksRepo.merge(task, body);
    return this.tasksRepo.save(task);
  }

  async remove(id: number) {
    await this.tasksRepo.delete(id);
    return true;
  }
}

12 Controller

import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';

import { TasksService } from './../services/tasks.service';

@Controller('api/tasks')
export class TasksController {

  constructor(
    private tasksService: TasksService
  ) {}

  @Get()
  findAll() {
    return this.tasksService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: number) {
    return this.tasksService.findOne(id);
  }

  @Post()
  create(@Body() body: any) {
    return this.tasksService.create(body);
  }

  @Put(':id')
  update(@Param('id') id: number, @Body() body: any) {
    return this.tasksService.update(id, body);
  }

  @Delete(':id')
  delete(@Param('id') id: number) {
    return this.tasksService.remove(id);
  }

}

13 Migrations

{
  "type": "postgres",
  "host": "localhost",
  "port": 5432,
  "username": "nico",
  "password": "postgres",
  "database": "my_db",
  "entities": ["src/**/*.entity.ts"],
  "synchronize": false,
  "migrationsTableName": "migrations",
  "migrations": ["src/database/migrations/*.ts"],
  "cli": {
    "migrationsDir": "src/database/migrations"
  }
}

14 Create mpm scripts

"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
"migrations:generate": "npm run typeorm -- migration:generate -n",
"migrations:run": "npm run typeorm -- migration:run",
"migrations:drop": "npm run typeorm -- schema:drop",
"migrations:show": "npm run typeorm -- migration:show"
npm run migrations:generate -- init
npm run migrations:run

15. Set entity

@CreateDateColumn({
  name: 'creation_at',
  type: 'timestamptz',
  default: () => 'CURRENT_TIMESTAMP',
})
creationAt: Date;

@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
updatedAt: Date;
npm run migrations:generate -- change-tasks
npm run migrations:run