NestJS에서는 컨트롤러에 쉽게 라우팅 설정이 가능합니다. 이때 다음과 같은 궁금증이 생겼습니다.
- /post/:id 과 /post/category 두 경로는 어떻게 구분하는거지?
- /post/:id 와 /post/1 두 경로가 모두 존재한다면 어느 경로로 이동되지?
오늘은 이렇게 헷갈리는 경우들을 모두 직접 테스트한 내용을 공유합니다.
(이전 글)
[NestJS] 컨트롤러에서 브레이크 포인트 안 걸릴 때 체크해야할 것들! ( 동적 경로, 정적 경로, route
저는 NestJS를 활용한 개발에 vscode를 이용하고 있습니다. 이때 vscode에는 브레이크 포인트(중단점)을 찍어서 디버깅할 수 있는 기능을 제공합니다. 그런데 가끔 Controller에 구현한 코드 위에 브레이
sparkit.tistory.com
정적 라우팅 vs 동적 라우팅
순서
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get('test')
async testRoute() {
return 'test';
}
@Get(':id')
async idRoute(@Param() id: number) {
return 'id';
}
}
다음과 같이 작성되어 있다면 의도는 다음과 같을 것입니다.
- /test GET 요청 --> testRoute 메서드 실행
- /1 GET 요청 --> idRoute 메서드 실행
이때 단순히 두 메서드 순서를 바꾸면 어떻게 될까요?
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get(':id')
async idRoute(@Param() id: number) {
return 'id';
}
@Get('test')
async testRoute() {
return 'test';
}
}
위와 같은 코드에서는 /test GET 요청을 보내도 idRoute가 실행되어 'id'가 반환될 것입니다. 왜 그럴까요? 그 이유는 동적 라우팅 메서드가 먼저 선언되었기 때문입니다. NestJS에서는 코드 상 위에 선언된 라우팅 메서드를 우선으로 적용하는 듯합니다. 이는 공식 문서를 확인해도 확인할 수 있습니다. 즉, 동적 라우팅은 정적 라우팅 이후에 적용해야 합니다.
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea
docs.nestjs.com
동적 라우팅 vs 동적 라우팅
순서
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get(':test')
async testRoute(@Param() test: number) {
return 'test';
}
@Get(':id')
async idRoute(@Param() id: number) {
return 'id';
}
}
위에서 언급했듯 라우팅 옵션의 선언 순서는 중요합니다. 이는 동적 라우팅 간 선언에도 동일하게 적용됩니다. 만약 위와 같이 동일한 구조의 동적 라우팅 메서드 2개가 존재한다면 /1 GET 요청 시 어떤 메서드가 실행될까요?
결과를 확인해보면 위 쪽에 먼저 선언된 testRoute 메서드가 실행되고 'test'를 반환하는 모습을 확인할 수 있습니다.
그럼 여기서 또 궁금한 부분이 생길 수 있습니다. 만약 동일하게 라우팅 변수를 이용하지만 그 타입이 다르다면 순서에 상관없이 작동할까요? 다음 예제를 확인합시다.
라우팅 변수 타입
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get(':id')
async idRoute(@Param() id: number) {
return 'id';
}
@Get(':test')
async testRoute(@Param() test: string) {
return 'test';
}
}
위 설명을 쭉 따라왔다면 순서만 따졌을 때 idRoute가 testRoute에 비해 먼저 선언되었으므로 /1 GET 요청을 보냈을 때 idRoute 메서드가 실행되는 것은 자명합니다. 하지만 이때 /abc GET 요청을 보낸다면 abc는 number 타입이 아니니까 알아서 testRoute 메서드에 연결되지 않을까요?
아닙니다. 아무리 라우팅 변수 타입을 정하더라도 결과는 변하지 않습니다. 왜 그럴까요?
일단 기본적으로 컨트롤러에서 @Param을 이용해 라우팅 변수를 받으면 string 타입으로 해당 변수를 받습니다. 그럼 number로 설정하면 이는 무슨 역할일까요? 이는 단순히 타입스크립트 컴파일러에서 타입 체크를 위해 설정한 값이지 실제 런타임에서는 아무런 역할이 없는 것과 같습니다. 그럼 라우팅 변수로 문자열만 받고 싶거나 숫자만 받고 싶을 때는 어떻게 할까요?
라우팅 변수 타입 설정하는 방법
라우팅 변수뿐만 아니라 쿼리 스트링으로 전달되는 값들이나 body로 전달되는 값 모두 포함되는 이야기입니다. 단순히 컨트롤러에서 해당 변수의 타입을 설정한다고 이것이 검증되거나 형변환되지 않습니다. 이를 위한 것이 바로 '파이프 혹은 DTO' 입니다. 간단한 예제로 라우팅 변수로 숫자만 받고 싶은 경우 설정법입니다.
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get(':id')
async idRoute(@Param('id', ParseIntPipe) id: number) {
return 'id';
}
}
ParseIntPipe은 NestJS에서 기본적으로 제공되는 파이프라인 기능입니다. 이를 통해 전달받은 라우팅 변수 id를 int 타입으로 설정할 수 있습니다. 그리고 만약 전달받은 값이 abc같은 문자열이라면 에러를 반환합니다.
DTO는 이런 파이프라인을 직접 구현하는 방식이라고 생각하면 됩니다. 관련 내용은 추후에 따로 다루겠습니다.
마무리
결과적으로 라우팅에서 가장 중요한 것은 선언 순서라는 것을 기억해주세요. 다음은 헷갈릴 수 있는 예제 몇 가지입니다. ( 모든 예제는 결과적으로 선언 순서가 중요하다는 사실을 알려줍니다 )
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get(':test/hello')
async dynamicRoute(@Param() test: string) {
return 'dynamic';
}
@Get('test/hello')
async staticRoute(@Param() test: string) {
return 'static';
}
}
- /test/hello GET 요청
'dynamic' 반환 - /abcd/hello GET 요청
'dynamic' 반환
# controller 코드 중 일부
@Controller('')
export class TestController {
@Get('test/hello')
async staticRoute(@Param() test: string) {
return 'static';
}
@Get(':test/hello')
async dynamicRoute(@Param() test: string) {
return 'dynamic';
}
}
- /test/hello GET 요청
'static' 반환 - /abcd/hello GET 요청
'dynamic' 반환
'백엔드 > NestJS' 카테고리의 다른 글
| [TypeORM] Join없이 외래키값만 간단히 활용하기 - @RelationId, @Column (0) | 2024.12.12 |
|---|---|
| [NestJS] 컨트롤러 파라미터 유효성 검증 방법 (Pipes, DTO, @Transform) (0) | 2024.12.04 |
| [NestJS] 컨트롤러에서 브레이크 포인트 안 걸릴 때 체크해야할 것들! ( 동적 경로, 정적 경로, route parameter ) (0) | 2024.11.25 |
| [NestJS]Jest를 이용해 테스트하자 - 1. 유닛 테스트(Unit Testing) (0) | 2024.11.12 |
| [NestJS]내장된 기능 활용해 마이크로서비스 구현하기 - 4. Kafka (0) | 2024.11.04 |