CRUD
CRUD
This chapter applies only to TypeScript
CRUD ํจํค์ง (@nestjsx/crud)๋ฅผ ์ฌ์ฉํ๋ฉด CRUD ์ปจํธ๋กค๋ฌ ๋ฐ ์๋น์ค๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ผ๋ฉฐ RESTful API๋ฅผ ์ํ ๋ค์ํ ๊ธฐ๋ฅ์ ์ฆ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ด๊ณ์์ด ํ์ฅ ๊ฐ๋ฅํ CRUD ์ปจํธ๋กค๋ฌ
ํํฐ๋ง, ํ์ด์ง ๋งค๊น, ์ ๋ ฌ, ๊ด๊ณ, ์ค์ฒฉ ๊ด๊ณ, ์บ์ ๋ฑ์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ ๋ฌธ์์ด ๊ตฌ๋ฌธ ๋ถ์
ํ๋ก ํธ ์๋ ์ฌ์ฉ์ ์ํ ์ฟผ๋ฆฌ ๋น๋๊ฐ ์๋ ํ๋ ์ ์ํฌ์ ๊ตฌ์ ๋ฐ์ง ์๋ ํจํค์ง
์ฟผ๋ฆฌ, ๊ฒฝ๋ก ๋งค๊ฐ ๋ณ์ ๋ฐ DTO ์ ํจ์ฑ ๊ฒ์ฌ
์ปจํธ๋กค๋ฌ ๋ฉ์๋๋ฅผ ์ฝ๊ฒ ์ฌ์ ์
์์ง๋ง ๊ฐ๋ ฅํ ๊ตฌ์ฑ (๊ธ๋ก๋ฒ ๊ตฌ์ฑ ํฌํจ)
์ถ๊ฐ ํฌํผ ๋ฐ์ฝ๋ ์ดํฐ
Swagger ๋คํ๋จผํธ
warning ์๋ฆผ ์ง๊ธ๊น์ง
@nestjsx/crud๋TypeORM๋ง ์ง์ํ์ง๋งSequelize๋ฐMongoose์ ๊ฐ์ ๋ค๋ฅธ ORM๋ ๊ฐ๊น์ด ์์ผ ๋ด์ ํฌํจ๋ ์์ ์ ๋๋ค. ๋ฐ๋ผ์ ์ด ๊ธฐ์ฌ์์๋TypeORM์ ์ฌ์ฉํ์ฌ CRUD ์ปจํธ๋กค๋ฌ ๋ฐ ์๋น์ค๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ค๋ช ํฉ๋๋ค.@nestjs/typeormํจํค์ง๋ฅผ ์ด๋ฏธ ์ฑ๊ณต์ ์ผ๋ก ์ค์นํ๊ณ ์ค์ ํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
Getting started
CRUD ๊ธฐ๋ฅ ์์ฑ์ ์์ํ๋ ค๋ฉด ํ์ํ ๋ชจ๋ ์ข ์์ฑ์ ์ค์นํด์ผ ํฉ๋๋ค.
npm i --save @nestjsx/crud @nestjsx/crud-typeorm class-transformer class-validatorํ๋ก์ ํธ์ ์ด๋ฏธ ์ผ๋ถ ์ํฐํฐ๊ฐ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
@@filename(hero.entity)
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Hero {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ type: 'number' })
power: number;
}์ฐ๋ฆฌ๊ฐ ํด์ผ ํ ์ฒซ๋ฒ์งธ ๋จ๊ณ๋ service๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค.
@@filename(heroes.service)
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { Hero } from './hero.entity';
@Injectable()
export class HeroesService extends TypeOrmCrudService<Hero> {
constructor(@InjectRepository(Hero) repo) {
super(repo);
}
}์๋น์ค๊ฐ ์๋ฃ๋์์ผ๋ฏ๋ก ์ปจํธ๋กค๋ฌ๋ฅผ ๋ง๋ค์ด ๋ด ์๋ค :
@@filename(heroes.controller)
import { Controller } from '@nestjs/common';
import { Crud } from '@nestjsx/crud';
import { Hero } from './hero.entity';
import { HeroesService } from './heroes.service';
@Crud({
model: {
type: Hero,
},
})
@Controller('heroes')
export class HeroesController {
constructor(public service: HeroesService) {}
}๋ง์ง๋ง์ผ๋ก ๋ชจ๋์ ๋ชจ๋ ๊ฒ์ ์ฐ๊ฒฐํด์ผํฉ๋๋ค.
@@filename(heroes.module)
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Hero } from './hero.entity';
import { HeroesService } from './heroes.service';
import { HeroesController } from './heroes.controller';
@Module({
imports: [TypeOrmModule.forFeature([Hero])],
providers: [HeroesService],
controllers: [HeroesController],
})
export class HeroesModule {}warning ์๋ฆผ
HeroesModule์ ๋ฃจํธApplicationModule๋ก ๊ฐ์ ธ ์ค๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค.
์ดํ์ Nest ์ ํ๋ฆฌ์ผ์ด์ ์๋ ๋ค์๊ณผ ๊ฐ์ด ์๋ก ์์ฑ๋ ์๋ ํฌ์ธํธ๊ฐ ์์ต๋๋ค.
GET /heroes- get many heroes.GET /heroes/:id- get one hero.POST /heroes/bulk- create many heroes.POST /heroes- create one hero.PATCH /heroes/:id- update one hero.PUT /heroes/:id- replace one hero.DELETE /heroes/:id- delete one hero.
Filtering and pagination
CRUD provides rich tools for filtering and pagination. Example request:
info Request GET /heroes?select=name&filter=power||gt||90&sort=name,ASC&page=1&limit=3
์ด ์์์๋ ํ์ด๋ก ๋ชฉ๋ก์ ์์ฒญํ๊ณ ํ์ด๋ก์ ํ์๊ฐ 90๋ณด๋ค ํฐ name์์ฑ๋ง ์ ํํ๊ณ 1 ํ์ด์ง ๋ด์์ ๊ฒฐ๊ณผ ์ ํ์ 3์ผ๋ก ์ค์ ํ์ต๋๋ค. ASC ์์๋ก name์ผ๋ก ์ ๋ ฌ๋ฉ๋๋ค.
์๋ต ๊ฐ์ฒด๋ ๋ค์๊ณผ ๋น์ทํฉ๋๋ค.
{
"data": [
{
"id": 2,
"name": "Batman"
},
{
"id": 4,
"name": "Flash"
},
{
"id": 3,
"name": "Superman"
}
],
"count": 3,
"total": 14,
"page": 1,
"pageCount": 5
}warning ์๋ฆผ ๊ธฐ๋ณธ ์ด์ ์์ฒญ ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ฆฌ์์ค ์๋ต ๊ฐ์ฒด์ ์ ์ง๋ฉ๋๋ค. ์ฐ๋ฆฌ์ ๊ฒฝ์ฐ์๋
id์ด์ ๋๋ค.
์ฟผ๋ฆฌ ๋งค๊ฐ ๋ณ์ ๋ฐ ํํฐ ์ฐ์ฐ์์ ์ ์ฒด ๋ชฉ๋ก์ ํ๋ก์ ํธ์ Wiki์์ ์ฐพ์ ์ ์์ต๋๋ค.
Relations
์ธ๊ธํ ๊ฐ์น๊ฐ ์๋ ๋ ๋ค๋ฅธ ๊ธฐ๋ฅ์ "๊ด๊ณ"์ ๋๋ค. CRUD ์ ์ด๊ธฐ์์ API ํธ์ถ ๋ด์์ ํ์นํ ์ ์๋ ์ํฐํฐ ๊ด๊ณ ๋ชฉ๋ก์ ์ง์ ํ ์ ์์ต๋๋ค.
@Crud({
model: {
type: Hero,
},
join: {
profile: {
exclude: ['secret'],
},
faction: {
eager: true,
only: ['name'],
},
},
})
@Controller('heroes')
export class HeroesController {
constructor(public service: HeroesService) {}
}@Crud()๋ฐ์ฝ๋ ์ดํฐ ์ต์
์์ ํ์ฉ๋ ๊ด๊ณ๋ฅผ ์ง์ ํ ํ ๋ค์๊ณผ ๊ฐ์ ์์ฒญ์ ํ ์ ์์ต๋๋ค.
info Request GET /heroes/25?join=profile||address,bio
์๋ต์๋ address ๋ฐ bio ์ด์ด ์ ํ๋๊ณ ๊ฒฐํฉ๋ ํ๋กํ์ผ์ ๊ฐ์ง hero ๊ฐ์ฒด๊ฐ ํฌํจ๋ฉ๋๋ค.
๋ํ ์๋ต์๋ eager: true๋ก ์ค์ ๋์ด ์์ผ๋ฏ๋ก ๋ชจ๋ ์๋ต์์ ์ง์๋๋ฏ๋ก name ์ด์ด ์ ํ๋ faction ์ค๋ธ์ ํธ๊ฐ ํฌํจ๋ฉ๋๋ค.
ํ๋ก์ ํธ์ WiKi์์ ๊ด๊ณ์ ๋ํ ์์ธํ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
Path params validation
๊ธฐ๋ณธ์ ์ผ๋ก CRUD๋ ์ด๋ฆ์ด id์ธ ์ฌ๋ฌ๊ทธ๋ฅผ ์์ฑํ๊ณ number๋ก ์ ํจ์ฑ์ ๊ฒ์ฌํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ด ๋์์ ๋ณ๊ฒฝํ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. ์ํฐํฐ์ ๊ธฐ๋ณธ ์ด _id (UUID ๋ฌธ์์ด)๊ฐ ์๊ณ ์ด๋ฅผ ์๋ ํฌ์ธํธ์ ์ฌ๋ฌ๊ทธ๋ก ์ฌ์ฉํด์ผ ํ๋ค๊ณ ๊ฐ์ ํ์ญ์์ค. ์ด ์ต์
์ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์์
์ ์ฝ๊ฒ ์ํํ ์ ์์ต๋๋ค.
@Crud({
model: {
type: Hero,
},
params: {
_id: {
field: '_id',
type: 'uuid',
primary: true,
},
},
})
@Controller('heroes')
export class HeroesController {
constructor(public service: HeroesService) {}
}๋ ๋ง์ params ์ต์ ์ ํ๋ก์ ํธ์ Wiki๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
Request body validation
์์ฒญ ๋ณธ๋ฌธ ์ ํจ์ฑ ๊ฒ์ฌ๋ ๊ฐ POST, PUT, PATCH ์์ฒญ์ Nest ValidationPipe๋ฅผ ์ ์ฉํ์ฌ ๊ธฐ๋ณธ์ ์ผ๋ก ์ํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ @Crud()๋ฐ์ฝ๋ ์ดํฐ ์ต์
์ model.type์ ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น์ ์ค๋ช
ํ๋ DTO๋ก ์ฌ์ฉํฉ๋๋ค.
์ด๋ฅผ ์ ๋๋ก ์ํํ๊ธฐ ์ํด validation groups๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@@filename(hero.entity)
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { IsOptional, IsDefined, IsString, IsNumber } from 'class-validator';
import { CrudValidationGroups } from '@nestjsx/crud';
const { CREATE, UPDATE } = CrudValidationGroups;
@Entity()
export class Hero {
@IsOptional({ always: true })
@PrimaryGeneratedColumn()
id: number;
@IsOptional({ groups: [UPDATE] })
@IsDefined({ groups: [CREATE] })
@IsString({ always: true })
@Column()
name: string;
@IsOptional({ groups: [UPDATE] })
@IsDefined({ groups: [CREATE] })
@IsNumber({}, { always: true })
@Column({ type: 'number' })
power: number;
}warning ์๋ฆผ
create๋ฐupdate์กฐ์น์ ๋ํด ๋ณ๋์ DTO ํด๋์ค๋ฅผ ์์ ํ ์ง์ํ๋ ๊ฒ์ ๋ค์ CRUD ๋ฆด๋ฆฌ์ค์ ์ฃผ์ ์ฐ์ ์์ ์ค ํ๋์ ๋๋ค.
Routes options
@Crud()๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ์ฉํ์ฌ ์์ฑ๋๋ ํน์ ๊ฒฝ๋ก๋ง ๋นํ์ฑํํ๊ฑฐ๋ ํ์ฑํ ํ ์ ์์ต๋๋ค.
@Crud({
model: {
type: Hero,
},
routes: {
only: ['getManyBase'],
getManyBase: {
decorators: [
UseGuards(HeroAuthGuard)
]
}
}
})
@Controller('heroes')
export class HeroesController {
constructor(public service: HeroesService) {}
}๋ํ ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํน์ ๊ฒฝ๋ก decorators ๋ฐฐ์ด์ ์ ๋ฌํ์ฌ ๋ชจ๋ ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ ๋ฉ์๋๋ฅผ ์ฌ ์ ์ํ์ง ์๊ณ ์ผ๋ถ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ถ๊ฐํ ๋ ํธ๋ฆฌํฉ๋๋ค.
Documentation
์ด ์ฑํฐ์ ์๋ CRUD ๊ธฐ๋ฅ ์ค ์ผ๋ถ๋ง ๋ค๋ฃน๋๋ค. ํ๋ก์ ํธ์ Wiki ํ์ด์ง์์ ๋ ๋ง์ ์ฌ์ฉ ์ง๋ฌธ์ ๋ํ ๋ต๋ณ์ ์ฐพ์ ์ ์์ต๋๋ค.
Last updated
Was this helpful?