NestJS 8.x/9.x 프레임워크용 Postgres 모듈 😻

이 게시물에서는 NestJS 😻용 Node PostgreSQL 모듈을 사용하는 방법을 설명합니다.
NestJS에 익숙하지 않거나 익숙하지 않은 사용자를 위해 효율적이고 확장 가능한 엔터프라이즈급 Node.js 응용 프로그램을 구축하는 데 도움이 되는 TypeScript Node.js 프레임워크입니다.

node-postgres을 사용해 본 적이 없는 사용자를 위해 PostgreSQL과 NodeJS를 통합하는 패키지입니다(PostgreSQL 및 해당 기능에 대한 자세한 내용은 here 참조).

이제 NestJS 앱 😻을 만들어 시작해 봅시다.
터미널을 열고 NestJS용 CLI를 설치합니다. 이미 설치되어 있으면 이 단계를 건너뜁니다.

$ npm i -g @nestjs/cli


그런 다음 NestJS 프로젝트를 만듭니다.




$ nest new app
$ cd app
// start the application
$ npm run start:dev

localhost:3000에서 브라우저를 열어 hello world가 표시되는지 확인합니다.

그런 다음 docker-compose.yml 파일을 생성하여 PostgreSQL 서비스를 생성합니다.

version: "3"

services:
  db:
    image: postgres
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: pass123
      POSTGRES_DB: nest


도커가 무엇인지 모르는 사람들을 위해 자세한 정보를 보려면 여기에 링크를 남겨둡니다Docker.
그럼 이제 패키지 설치를 진행해 볼까요?

PostgresModule 및 Node-Postgres 종속성 설치



$ npm install --save nest-postgres pg

AppModule에서 PostgresModule 설정

import { Module } from '@nestjs/common';
import { PostgresModule } from 'nest-postgres';

@Module ({
   imports: [
    PostgresModule.forRoot({
        connectionString: 'postgresql://postgres:pass123@localhost:5432/nest',
        // or
        // host: 'localhost',
        // database: 'nest',
        // password: 'pass123',
        // user: 'postgres',
        // port: 5432,
    }),
   ],
})
export class AppModule {}


이제 REST API를 만들고 사용자라고 부르겠습니다. 터미널을 열고 명령을 실행하여 사용자를 위한 모듈, 서비스 및 컨트롤러를 생성합니다.

$ nest g mo users  # module
$ nest g s users   # service
$ nest g co users  # controller


사용자 모듈:

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  controllers: [UsersController],
  providers: [UsersService]
})
export class UsersModule {}


API 구축을 시작하기 전에 Data Transfer Objects(Dto) 클래스를 생성하여 사용자를 생성합니다.

import { IsEmail, IsNotEmpty, IsString } from "class-validator";

export class CreateUserDto {
    @Notempty()
    @IsString()
    firstName: string;

    @Notempty()
    @IsString()
    lastName: string;

    @Notempty()
    @IsString()
    @IsEmail()
    email: string;
}


업그레이드를 위한 dto 클래스를 만들기 전에 이 패키지를 설치해야 합니다.

$ npm i @nestjs/mapped-types


이제 사용자 데이터를 업데이트하기 위해 CreateUserDto 클래스를 확장합니다.

import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';

export class UpdateUserDto extends PartialType(CreateUserDto){}


그런 다음 UserService를 구현합니다.

import {
  BadRequestException,
  HttpException,
  HttpStatus,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { Client } from 'pg';
import { InjectClient } from 'nest-postgres';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UsersService {
  constructor(@InjectClient() private readonly pg: Client) {}

  public async findAll(): Promise<any> {
    const users = await this.pg.query('SELECT * FROM users');
    return users.rows;
  }

  public async findOne(id: string): Promise<any> {
    if (!id) {
      throw new BadRequestException();
    }

    const result = await this.pg.query('SELECT * FROM users WHERE id=$1', [id]);

    if (!result) {
      throw new NotFoundException();
    }

    return result.rows;
  }

  public async create(createUserDto: CreateUserDto): Promise<any> {
    try {
      const user = await this.pg.query(
        'INSERT INTO users (firstName, lastName, email)  VALUES ($1, $2, $3) RETURNING *',
        [createUserDto.firstName, createUserDto.lastName, createUserDto.email],
      );
      return user.rows;
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async update(id: number, updateUserDto: UpdateUserDto): Promise<any> {
    try {
      const users = await this.pg.query(
        'UPDATE users SET firstName=$1, lastName=$2, email=$3 WHERE id=$3 RETURNING *',
        [updateUserDto.firstName, updateUserDto.lastName, updateUserDto.email, id],
      );
      return users.rows;
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async remove(id: string): Promise<void[]> {
    if (!id) {
      throw new BadRequestException();
    }

    const users = await this.pg.query(
      'DELETE FROM users WHERE id=$1 RETURNING *',
      [id],
    );
    return users.rows;
  }
}

UsersService를 더 개선하기 위해 다음과 같이 모든 쿼리를 이동하는 저장소를 만들 수 있습니다.

import {
  BadRequestException,
  HttpException,
  HttpStatus,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { Client } from 'pg';
import { InjectClient } from 'nest-postgres';
import { CreateUserDto } from '../dto/create-user.dto';
import { UpdateUserDto } from '../dto/update-user.dto';
import { User } from '../interfaces/user.interface';

@Injectable()
export class UsersRepository {
  constructor(@InjectClient() private readonly pg: Client) {}

  public async selectAll(): Promise<User[]> {
    const users = await this.pg.query('SELECT * FROM users');
    return users.rows;
  }

  public async selectOne(id: string): Promise<User[]> {
    if (!id) {
      throw new BadRequestException();
    }

    const result = await this.pg.query('SELECT * FROM users WHERE id=$1', [id]);

    if (!result) {
      throw new NotFoundException();
    }

    return result.rows;
  }

  public async create(createUserDto: CreateUserDto): Promise<User[]> {
    try {
      const { firstName, lastName, email } = createUserDto;
      const user = await this.pg.query(
        'INSERT INTO users (firstName, lastName, email)  VALUES ($1, $2, $3) RETURNING *',
        [firstName, lastName, email],
      );
      return user.rows;
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async update(
    id: number,
    updateUserDto: UpdateUserDto,
  ): Promise<User[]> {
    try {
      const { firstName, lastName } = updateUserDto;

      const users = await this.pg.query(
        'UPDATE users SET firstName=$1, lastName=$2, email=$3 WHERE id=$4 RETURNING *',
        [firstName, lastName, email, id],
      );
      return users.rows;
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async delete(id: string): Promise<void[]> {
    if (!id) {
      throw new BadRequestException();
    }

    const users = await this.pg.query(
      'DELETE FROM users WHERE id=$1 RETURNING *',
      [id],
    );
    return users.rows;
  }
}


이제 다음과 같이 UsersService를 다시 편집해 보겠습니다.

import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './interfaces/user.interface';
import { UsersRepository } from './repositories/users.repository';

@Injectable()
export class UsersService {
  constructor(private usersRepository: UsersRepository) {}

  public async findAll(): Promise<User[]> {
    return this.usersRepository.selectAll();
  }

  public async findOne(id: string): Promise<User[]> {
    return this.usersRepository.selectOne(id);
  }

  public async create(createUserDto: CreateUserDto): Promise<User[]> {
    try {
      return this.usersRepository.create(createUserDto);
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async update(
    id: number,
    updateUserDto: UpdateUserDto,
  ): Promise<User[]> {
    try {
      return this.usersRepository.update(id, updateUserDto);
    } catch (err) {
      throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
  }

  public async remove(id: string): Promise<void[]> {
    return this.usersRepository.delete(id);
  }
}


이제 다음과 같이 공급자 UsersRepository를 UserModule에 추가합니다.

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { UsersRepository } from './repositories/users.repository';

@Module({
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
})
export class UsersModule {}


이제 우리의 것을 구현해 봅시다UsersController.

import {
  Controller,
  Get,
  Post,
  Body,
  Put,
  Param,
  Delete,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './interfaces/user.interface';

@Controller('user')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto): Promise<User[]> {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User[]> {
    return this.usersService.findOne(id);
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() updateUserDto: UpdateUserDto,
  ): Promise<User[]> {
    return this.usersService.update(+id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<void[]> {
    return this.usersService.remove(id);
  }
}


이제 모든 것이 완벽하게 작동하는지 API를 테스트해야 합니다.

    $ curl -H 'content-type: application/json' -v -X GET http://127.0.0.1:3000/api/users  
    $ curl -H 'content-type: application/json' -v -X GET http://127.0.0.1:3000/api/users/:id 
    $ curl -H 'content-type: application/json' -v -X POST -d '{"firstName": "firstName #1", "lastName": "lastName #1", "email": "[email protected]"}' http://127.0.0.1:3000/api/users 
    $ curl -H 'content-type: application/json' -v -X PUT -d '{"firstName": "firstName update #1", "lastName": "lastName update #1", "email": "[email protected]}' http://127.0.0.1:3000/api/users/:id 
    $ curl -H 'content-type: application/json' -v -X DELETE http://127.0.0.1:3000/api/users/:id 

node-postgres에 대한 자세한 내용은 here을 참조하십시오.

위에 작성된 코드는 아마도 orm에서 typeorm 등으로 온 사람들이 패키지의 기능을 보여주는 예일 뿐이라는 점을 지적합니다.
귀하의 필요와 기능에 가장 적합한 방식을 선택하십시오.

이 모듈은 NestJS 😻 버전 7.x와 호환됩니다.

그게 다야 😀
귀하의 프로젝트에 유용할 수 있기를 바랍니다.
무엇이든 의견에 저를 쓰십시오 😉

좋은 웹페이지 즐겨찾기