> For the complete documentation index, see [llms.txt](https://jakekwak.gitbook.io/nestjs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jakekwak.gitbook.io/nestjs/recipes/untitled-8.md).

# CRUD

## CRUD

### This chapter applies only to TypeScript

[CRUD](https://github.com/nestjsx/crud) 패키지 (`@nestjsx/crud`)를 사용하면 CRUD 컨트롤러 및 서비스를 쉽게 만들 수 있으며 RESTful API를 위한 다양한 기능을 즉시 사용할 수 있습니다.

* 데이터베이스에 관계없이 확장 가능한 CRUD 컨트롤러
* 필터링, 페이지 매김, 정렬, 관계, 중첩 관계, 캐시 등을 사용하여 쿼리 문자열 구문 분석
* 프론트 엔드 사용을 위한 쿼리 빌더가 있는 프레임 워크에 구애받지 않는 패키지
* 쿼리, 경로 매개 변수 및 DTO 유효성 검사
* 컨트롤러 메소드를 쉽게 재정의
* 작지만 강력한 구성 (글로벌 구성 포함)
* 추가 헬퍼 데코레이터
* Swagger 다큐먼트

> warning **알림** 지금까지`@nestjsx/crud`는 `TypeORM` 만 지원하지만 `Sequelize` 및 `Mongoose`와 같은 다른 ORM도 가까운 시일 내에 포함될 예정입니다. 따라서 이 기사에서는 `TypeORM`을 사용하여 CRUD 컨트롤러 및 서비스를 작성하는 방법에 대해 설명합니다. `@nestjs/typeorm` 패키지를 이미 성공적으로 설치하고 설정했다고 가정합니다. 자세한 내용은 [여기](https://app.gitbook.com/techniques/sql)를 참조하십시오.

## Getting started

CRUD 기능 생성을 시작하려면 필요한 모든 종속성을 설치해야 합니다.

```bash
npm i --save @nestjsx/crud @nestjsx/crud-typeorm class-transformer class-validator
```

프로젝트에 이미 일부 **엔터티**가 있다고 가정합니다.

```typescript
@@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**를 만드는 것입니다.

```typescript
@@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);
  }
}
```

서비스가 완료되었으므로 **컨트롤러**를 만들어 봅시다 :

```typescript
@@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) {}
}
```

마지막으로 **모듈**에 모든 것을 연결해야합니다.

```typescript
@@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](https://github.com/nestjsx/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`으로 정렬됩니다.

응답 객체는 다음과 비슷합니다.

```javascript
{
  "data": [
    {
      "id": 2,
      "name": "Batman"
    },
    {
      "id": 4,
      "name": "Flash"
    },
    {
      "id": 3,
      "name": "Superman"
    }
  ],
  "count": 3,
  "total": 14,
  "page": 1,
  "pageCount": 5
}
```

> warning **알림** 기본 열은 요청 여부에 관계없이 리소스 응답 개체에 유지됩니다. 우리의 경우에는 `id` 열입니다.

쿼리 매개 변수 및 필터 연산자의 전체 목록은 프로젝트의 [Wiki](https://github.com/nestjsx/crud/wiki/Requests)에서 찾을 수 있습니다.

## Relations

언급할 가치가 있는 또 다른 기능은 "관계"입니다. CRUD 제어기에서 API 호출 내에서 페치할 수 있는 엔티티 관계 목록을 지정할 수 있습니다.

```typescript
@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](https://github.com/nestjsx/crud/wiki/Controllers#join)에서 관계에 대한 자세한 정보를 찾을 수 있습니다.

## Path params validation

기본적으로 [CRUD](https://github.com/nestjsx/crud)는 이름이 `id`인 슬러그를 생성하고 `number`로 유효성을 검사합니다.

그러나 이 동작을 변경할 가능성이 있습니다. 엔티티에 기본 열 `_id` (UUID 문자열)가 있고 이를 엔드 포인트의 슬러그로 사용해야 한다고 가정하십시오. 이 옵션을 사용하면 다음과 같은 작업을 쉽게 수행할 수 있습니다.

```typescript
@Crud({
  model: {
    type: Hero,
  },
  params: {
    _id: {
      field: '_id',
      type: 'uuid',
      primary: true,
    },
  },
})
@Controller('heroes')
export class HeroesController {
  constructor(public service: HeroesService) {}
}
```

더 많은 params 옵션은 프로젝트의 [Wiki](https://github.com/nestjsx/crud/wiki/Controllers#params)를 참조하십시오.

## Request body validation

요청 본문 유효성 검사는 각 POST, PUT, PATCH 요청에 Nest `ValidationPipe`를 적용하여 기본적으로 수행됩니다. 우리는 `@Crud()`데코레이터 옵션의 `model.type`을 유효성 검사 규칙을 설명하는 DTO로 사용합니다.

이를 제대로 수행하기 위해 [validation groups](https://github.com/typestack/class-validator#validation-groups)를 사용합니다.

```typescript
@@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](https://github.com/nestjsx/crud) 릴리스의 주요 우선 순위 중 하나입니다.

## Routes options

`@Crud()`데코레이터를 적용하여 생성되는 특정 경로만 비활성화하거나 활성화 할 수 있습니다.

```typescript
@Crud({
  model: {
    type: Hero,
  },
  routes: {
    only: ['getManyBase'],
    getManyBase: {
      decorators: [
        UseGuards(HeroAuthGuard)
      ]
    }
  }
})
@Controller('heroes')
export class HeroesController {
  constructor(public service: HeroesService) {}
}
```

또한 메소드 데코레이터를 특정 경로 `decorators` 배열에 전달하여 모든 메소드 데코레이터를 적용할 수 있습니다. 기본 메소드를 재 정의하지 않고 일부 데코레이터를 추가할 때 편리합니다.

## Documentation

이 챕터의 예는 [CRUD](https://github.com/nestjsx/crud) 기능 중 일부만 다룹니다. 프로젝트의 [Wiki](https://github.com/nestjsx/crud/wiki/Home) 페이지에서 더 많은 사용 질문에 대한 답변을 찾을 수 있습니다.
