Nest 공식문서 Controllers

First Steps

main.ts : NestFactory 를 써서 Nest Application Instance를 생성함

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

//const app = await NestFactory.create<NestExpressApplication>(AppModule);

에서 create는 INestApplication interface를 반환함.
listen을 하기만 하면 바로 뒤에 나오는 inbound포트를 listen 하기 시작함

밑에 코드처럼 <NestExpressApplication>
<NestFastifyApplication> 넘기면, Express 혹은 Fastify 로 코드를 확실하게 특정지을 수 있다.

특정 패키지에 있는 메서드를 무조건 쓰고 싶은 것이 아니라면 권장되지 않는다.

Controllers

생성, 요약

client로부터 온 요청을 받고, 응답을 되돌려 주는 역할을 하게 됨. express 의 router과 유사한 기능.
클래스 decorator를 이용해 생성할 수 있다.
빠른 생성을 위해서는
nest g Controller
CRUD작업을 위해서는 nest g resources

import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

이것 처럼 @Controller 안에 문자열 혹은 *(wildcard)를 넣으면 그 경로로 오는 요청을 핸들링 하게 됨
@Controller와 @Get, @Post...같은 것 뒤에 아무것도 넣지 않으면 루트 경로로 오는 것을 핸들링. 넣으면 그 경로로 오는 것을 핸들링. 단 Controller의 문자열/Get의 문자열 순서로 연결됨
Ex) @Controller("hello") @Post("world")
=> Post hello/world 경로의 요청
메서드의 이름은 전혀 중요하지 않음 그냥 그 함수가 실행된다고 적을 뿐인 정도
기본 return status : 200(Post는 201)

같이 쓰이는 데코레이터

@HttpCode 데코레이터로 status를 바꿀 수 있음
return 방식은 2가지
1. Standard :
객체를 반환하는 경우는 JSON화 되고, 원시 타입을 반환하면 그냥 값만 반환함. express res같은 것들을 이용하지 않음
2. Library-specific
@Res 같은 것을 사용해서 라이브러리에만 있는 함수들을 사용하는 것
단. @Res나 @Next간은 것을 사용하면 라이브러리에 종속적인 코드라는 것을 인지하고, 표준 처리를 해주지 않게됨.
하지만 @Res도 사용하고, 표준 처리도 하고 싶을 때(쿠키만 세팅하는 경우...) @Res({passthrough:true}) 데코레이터를 사용하면

클래스에 있는 메서드의 파라미터에 @Req, @Next, 같은 것을 넣으면 자동으로 그것에 해당하는 것을 nest가 넣어줌. @Body,@Session, @Param, @Body, @Query, @Header, @Ip, @HostParam 이때 Param, Body, Query, Header는 모두 다 안에 문자열을 넣고, 그것에 해당하는 것만 받아올 수 있음.
@Body("hello") => req.body["hello"]
Res사용시 당연하지만 반환을 해야함. 아니면 서버가 정지함
?, +,*, ()는 route경로에 사용될 수 있고, 정규 표현식으로 처리됨. 반대로 -, . 은 그냥 문자열로 쓰임

변수에 따라 반환 코드가 달라지는 것은 Res객체를 사용하는 것이 대표적이다.
혹은 에러 처리의 경우는 exception을 throw하고, catch하는 exception filter를 통해 처리 할 수 있다

헤더 처리는 @Header("name","value") 로 쓸 수 있다.
혹은 res.header()도 가능

Redirection
@Redirect("주소"{,주소=302}) 생략시 302로, 아니면 코드 지정 가능
만약 동적으로 코드를 바꾸고 싶다면

{
  "url": string,
  "statusCode": number
}

형태로 되어 있는 객체를 리턴 해버리면 됨

@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
  if (version && version === '5') {
    return { url: 'https://docs.nestjs.com/v5/' };
  }
}

이런 방식으로 했을 경우 버전에 따라 다른 곳으로 보내도록 override할 수 있다.
Parameter

@Get(':id')
findOne(@Param('id') id: string): string {
  return `This action returns a #${id} cat`;
}

같은 것으로 파라미터를 가져올 수 있다.

SubDomainRouting

@Controller({ host: 'admin.example.com' })
export class AdminController {
  @Get()
  index(): string {
    return 'Admin page';
  }
}

이 코드로 특정 도메인에서 온 요청이 확인되면 특정 값을 반환할 수 있습니다.
단 Fastify는 이를 할 수 없기에, Express의 adaptor가 대신에 사용될 것입니다

@Controller({ host: ':account.example.com' })
export class AccountController {
  @Get()
  getInfo(@HostParam('account') account: string) {
    return account;
  }
}

host의 parameter로도 값을 받을 수 있습니다.
Scope
db에 connecting할 때, singleton 기법을 이용해 전역 관리를 합니다. 이런 경우 안전함을 보장할 수 있습니다.
단 예외로는 request를 기본으로한 GraphQL의 경우 request tracking 이나 multy-tenancy일 때 문제가 날 수 있습니다. 이는 여기서 확인할 수 있습니다.

Asyncronicity.
최신 JS문법이 거의 대부분 비동기를 지원하거나, 비동기 이기에, async문법 역시 지원합니다.
Nest가 알아서 resolve를 기다립니다.

@Get()
async findAll(): Promise<any[]> {
  return [];
}

RxJS에 observable stream 도 끝났을 때를 기다려 처리할 수 있습니다.

@Get()
findAll(): Observable<any[]> {
  return of([]);
}

Request Payloads
@Body 데코레이터를 사용지만, DTO(Data Transfer Object)를 만들어서 처리함. interface나 class를 통해 DTO를 만들 수 있다. 이때 class를 통해 하는 것을 권장하는데, runtime에서 interface(js가 정식 지원하지 않기에)는 날아가지만, class는 남아 있기에, runtime 에서 검증을 해줄 수 있다는 장점이 있다.

export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return 'This action adds a new cat';
}

ValidationPipe가 여기서 특정 값만 받을 수 있도록 처리를 해줌. whitelist를 해줌.
간단한 nest controller

import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';

@Controller('cats')
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return 'This action adds a new cat';
  }

  @Get()
  findAll(@Query() query: ListAllEntities) {
    return `This action returns all cats (limit: ${query.limit} items)`;
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return `This action returns a #${id} cat`;
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
    return `This action updates a #${id} cat`;
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return `This action removes a #${id} cat`;
  }
}

nest cli를 통해서 그나마 간단하게 세팅 가능함
$ nest g resource

이렇게 Controller를 만들어도, Nest는 Controller가 있다는 것을 모르기에, app.module.ts 에서 등록 과정을 거침

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';

@Module({
  controllers: [CatsController],
})
export class AppModule {}

과정으로 등록 가능


@Controller('cats')
export class CatsController {
  @Post()
  create(@Res() res: Response) {
    res.status(HttpStatus.CREATED).send();
  }

  @Get()
  findAll(@Res() res: Response) {
     res.status(HttpStatus.OK).json([]);
  }
}

library specific으로


@Controller('cats')
export class CatsController {
  @Post()
  create(@Res() res: Response) {
    res.status(HttpStatus.CREATED).send();
  }

  @Get()
  findAll(@Res() res: Response) {
     res.status(HttpStatus.OK).json([]);
  }
}

이런 것도 가능함

좋은 웹페이지 즐겨찾기