일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Spring
- 코딩테스트
- REST API
- JWT
- 프로그래머스
- Interceptor
- node.js
- LifeCycle
- typescript
- dfs
- MySQL
- winston
- javascript
- Deep Dive
- 알고리즘
- Kubernetes
- css
- puppeteer
- bean
- 인접행렬
- html
- 자료구조
- 탐욕법
- 인접리스트
- TIL
- Linux
- nestjs
- GraphQL
- java
- OOP
- Today
- Total
처음부터 차근차근
[NestJS] Controller 본문
Controller란?
Controllers are responsible for handling incoming requests and returning responses to the client.
-> 들어오는 요청에 반응하고, 적절한 응답을 보낸다.
- 컨트롤러의 목적은 특정 요청에 응답을 반환하는 것
- 여기서 routing mechanism이 도입되는데, 이것은 어떠한 요청에 어떤 컨트롤러가 반응할 지 결정한다.
- 각각의 컨트롤러는 하나 이상의 route를 가지고, 각각의 route는 다른 행동을 수행할 수 있다.
Nest에서는 기본적으로 decorator를 통해 컨트롤러를 생성한다.
Decorators associate classes with required metadata and enable Nest to create a routing map.
➡️ 데코레이터는 class들을 연관지어주는데, 필요한 메타데이터와 Nest가 ruoting map을 그려주게 연관지어준다.
Routing
NestJS의 컨트롤러 사용법을 알아보기 전 Express에서 어떻게 동작시켰는지 알아보자.
// app.METHOD(Path, HANDLER)
app.get('/', (req, res) => {
res.send('Hello World!');
});
- app.get method 작성한다.
- get method에 내부 인자로 Path와 Handler를 작성한다.
- 해당 Route를 동작시켰을때 동작 로직을 내부에 구현한다.
혹은 계층 아키텍쳐 패턴을 적용했을 때 Contoller와 Service, Router를 구분해서 작성도 가능하다.
그러나 NestJS는 Router를 작성할 필요가 없다. 예시를 통해 확인하자.
import { Controller, Get } from '@nestjs/common';
// Controller의 Path를 내부 인자로 지정할 수 있다.
@Controller('cats')
export class CatsController {
// GET /cats
// GET 데코레이터를 통해 endpoint를 지정할 수 있다.
@Get()
findAll(): string {
return 'This action returns all cats';
}
// GET /cats/breed
@Get('breed')
findAllBreed(): string {
return 'This.action returns all Breed';
}
}
- @Get() 데코레이터를 통해 Nest가 자동으로 해당하는 Path의 HTTP endpoint 핸들러를 만들어낸다.
- Path는 Controller에서도 지정할 수 있지만, Request method decorator(@Get(), @Post() 등)을 통해서도 지정할 수 있다.
Controller 동작시키기
해당 예시를 통해 Controller를 작성해도, Nest 동작 시 Controller가 작동하지 않는다.
그 이유는 Module에 등록하지 않았기 때문이다.
해당 컨트롤러를 모듈에 등록시키는 방법은 단순하다.
아래 예시와 같이 해당 모듈에 Controller를 등록시키면 된다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
@Module({
controllers: [CatsController],
})
export class AppModule {}
응답 처리 방식
Standard
- Nest의 HTTP method 데코레이터는 기본적으로 method의 return을 통해 응답을 반환한다.
- Built-in Method 데코레이터를 통해서 작성할 경우, 자동으로 응답이 JSON으로 직렬화된다.
- 원시값의 경우 직렬화를 거치지 않고 반환한다.
- StatusCode는 200으로 고정되어 있으며 Post의 경우 201로 동작한다.
Library-specific(예시 : Express)
- 라이브러리를 통해 response object를 반환할 수 있다.
export class CatsController {
@Post()
create(@Res() res: Response) {
res.status(HttpStatus.CREATED).send();
}
@Get()
findAll(@Res() res: Response) {
res.status(HttpStatus.OK).json([]);
}
}
- 해당 예시는 Response를 Express 라이브러리에서 주입받아 사용하고 있다.
- @Res decorator를 사용해서 응답을 줄 수 있다.
- @Res(), @Next()와 같은 라이브러리 종속적인 기능을 사용하면 NestJS는 자동으로 이걸 인식하고 해당 핸들러에 대해서만 Standard 처리 방식을 비활성화함 (둘 다 같이 사용하고 싶으면 @Res({ passthrough: true })와 같이 옵션을 설정해줘야 함)
Request object
@Req 데코레이터를 통해 요청 객체를 다음과 같이 받을 수 있다.
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
return 'This action returns all cats';
}
}
그러나, 요청 객체를 전부 받아오는 것은 불필요하며, Nest에서는 @Body만 받아오거나, @Query, @Params만 받아올 수 있는 데코레이터를 지원하고 있다.
@Request(), @Req() | req |
@Response(), @Res()* | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
@Ip() | req.ip |
@HostParam() | req.hosts |
@Res, @Response는 Library-specific Mode(예시 : Express)를 사용할 경우 권장한다.
Resource
Nest는 decorator를 통해 다양한 메서드를 지원한다.
- @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), @Head()
- 추가적으로, @All() 메서드를 통해 특정 엔드포인트의 모든 메서드를 한번에 처리할 수 있다.
Route wildcards
다음 예시를 보자.
@Get('ab*cd')
findAll() {
return 'This route uses a wildcard';
}
@Get 메서드 안에 'ab*cd' path route로 등록되어 있다. 이는 abcd, ab_cd, abecd 등 다양한 path를 모두 받을 수 있다.
메서드 안에 ?, +, * 과 같은 정규식 표현이 사용 가능하다.
Status Code
StatusCode는 200으로 고정되어 있으며, 예외적으로 Post는 201이다. 하지만 @HttpCode()데코레이터를 통해 상태코드를 변경할 수 있다.
@Post()
// HttpCode 데코레이터를 통해 해당 StatusCode를 반환
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
만약 다양한 응답이 있을 경우, @Res() 를 사용하여 응답하는 것이 좋다.
(혹은 Exception 을 통해 처리하는 방법도 있다.)
Headers
@Header() 데코레이터를 통해 응답 헤더를 추가할 수 있다.
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action adds a new cat';
}
Redirection
@Redirect() 데코레이터를 통해 redirection을 할 수 있다. 인자는 url과 statusCode가 들어간다.
@Get()
@Redirect('https://nestjs.com', 301)
혹은 Return value를 받아서 override를 할 수 있다.
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
// Override 가능
return { url: 'https://docs.nestjs.com/v5/' };
}
}
Route parameters
Http method decorator 안에 받을 parameter를 입력하여 동적으로 parameter 데이터를 받을 수 있다.
예시로 GET /cats/1 을 받는다고 가정하자.
// parameter key 입력
@Get(':id')
// @Param() 데코레이터를 통해 route 매개변수를 받는다.
findOne(@Param() params: any): string {
console.log(params.id);
return `This action returns a #${params.id} cat`;
}
@Get(':id')
// 혹은 데코레이터 안에 받을 route 매개변수를 입력하여 해당 매개변수만 받을 수 있다.
findOne(@Param('id') id: string): string {
return `This action returns a #${id} cat`;
}
두 가지 방법을 통해 URL의 매개변수를 받았다.
이처럼 @Param 데코레이터를 통해 URL 매개변수를 받을 수 있다.
Sub-Domain Routing
// host를 설정해서 서브 도메인을 받을 수 있다.
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
@Controller에 host option을 추가하여 서브 도메인을 추가할 수 있다. 이를 통해 요청 호스트에 따라 다른 요청을 받을 수 있다.
또한 매개변수값을 통해 동적으로 받을 수 있다.
@Controller({ host: ':account.example.com' })
export class AccountController {
@Get()
// @HostParam 데코레이터를 통해 매개변수로 받는다.
getInfo(@HostParam('account') account: string) {
return account;
}
}
Scope
- NestJS는 거의 대부분의 자원이 모든 요청들과 공유됨 (DB 커넥션풀, singleton service)
- Node.js 특성상 각 요청마다 별도의 스레드로 처리하는 멀티 스레드 방식이 아니기 때문에 singleton 객체를 공유하는게 안전함
- 하지만, 요청 단위의 생명주기가 필요한 엣지 케이스들이 있는데 이럴땐 scope를 다르게 설정해주면 됨
Asynchronicity
- 핸들러에 async를 적용하여 비동기 처리가 가능함(Promise 반환)
@Get()
async findAll(): Promise<any[]> {
return [];
}
- RxJS의 observable 반환도 가능.
@Get()
findAll(): Observable<any[]> {
return of([]);
}
Request payload
Post Method는 데이터를 Param으로 받지 않고 Body를 통해 받는다.
이때 DTO(Data Transfer Object) schema를 통해 받아야하는 데이터 타입을 명시해줄 수 있다.
NestJS에서는 Class로 DTO로 사용할 것을 권장한다. (interface는 트랜스파일 과정에서 사라지므로 NestJS가 런타임에서 refer할 수 없음 - Pipes 같은 기능에서 해당 특징이 중요함)
export class CreateCatDto {
name: string;
age: number;
breed: string;
}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
'FrameWork > NestJS' 카테고리의 다른 글
[NestJS] Middleware (0) | 2023.11.25 |
---|---|
[NestJS] Request Lifecycle (0) | 2023.11.25 |
[NestJS] Module (1) | 2023.11.24 |
[NestJS] Providers (0) | 2023.11.24 |
[NestJS] NestJS는 왜 만들어졌을까?? (1) | 2023.11.13 |