NestJS - 2편 (설치~인터페이스)
설치
npm i -g @nestjs/cli
NestJS generator 설치nest new project-name
NestJS generator로 새 프로젝트 생성
여기서 폴더구조 쫌 살펴보면 @Controller가 보인다. 엥? 내가 생각하는 그 스프링 어노테이션 컨트롤러가 맞나? 정답: 맞다..npm i
필요한 패키지 설치npm start
컨트롤러
MVC(Model View Controller)패턴의 컨트롤러가 맞다.
Request, Response를 처리한다.
코드로 이해해보자nest g controller [name]
해보면 띠용? 컨트롤러가 알아서 생성되고 메인 모듈인 app.module.ts
에도 알아서 컨트롤러가 등록된다.
컨트롤러 뿐만이 아니다.nest -h
로 생성 가능한 명령어들을 볼 수 있고,nest g resource [name]
로 한번에 CRUD 샘플(module, controller, service, entity, dto, 심지어 테스트 코드까지)을 빠르게 만들 수 있다.
Java Spring 개발해오면서 매번 폴더 새로 만들어주고 생성했던 나에게 충격이었다. 아니 왜케 편해??
스프링에도 있었을거같은데 매번 하나하나 새로 만들던 내가 멍청하게 느껴졌다..
라우팅
우선 코드를 한 번 살펴보자app.contorller.ts
파일
스프링이랑 완전 똑같다...
@Controller 이 어노테이션 선언해서 이게 컨트롤러임을 알게해주듯 여기서도 똑같다. 여기서는 어노테이션 대신 데코레이터라고 한다.
어노테이션 선언 후 ()안에 '/url'을 적어 해당 url로 오는 요청이 처리 가능하다.
위에 어노테이션이 선언되어있다면 아래 함수명은 어떤걸로 하든 무방하다.
(일반적으로 사내 네이밍 규칙을 따름..)
url 선언시 @Get('he*lo')
등으로 *,?,+,()등... 정규표현식의 와일드카드도 작동한다. helo
, hello
, he__lo
등으로 호출이 가능하다.
Request Object
클라이언트로부터 온 데이터(객체로 Nest가 변환해줌)를 다루는 방법 @Req()
@Get()
getHello(@Req() req: Request): string {
console.log(req);
return this.appService.getHello();
}
하지만 실제로 API 개발시 직접 객체를 다루는 일은 드물다.@Query()
, @Param(key?: string)
, @Body
등의 데코레이터를 이용해 요청에 포함된 쿼리 파라미터, 패스 파라미터, 본문내용을 쉽게 받을 수 있도록 해준다.
Response
자 이번에 앞에서 맛만본 nest g resource [name]
를 실제로 써보자nest g resource Users
실행하고 서버를 실행해보자. npm start
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RoutesResolver] UsersController {/users}: +0ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RouterExplorer] Mapped {/users, POST} route +2ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RouterExplorer] Mapped {/users, GET} route +0ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RouterExplorer] Mapped {/users/:id, GET} route +1ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RouterExplorer] Mapped {/users/:id, PATCH} route +1ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [RouterExplorer] Mapped {/users/:id, DELETE} route +1ms
[Nest] 9392 - 2022. 04. 18. 오후 4:39:17 LOG [NestApplication] Nest application successfully started +3ms
이렇게 터미널에 현재 어떤 라우팅으로 요청 받을 수 있는지 확인이 가능하다.
나는 API Tester로 VSCode의 Extension인 REST Client를 주로 이용하는데 원하는 위치 아무곳에나 파일 생성하고 확장자를 .http
로 적으면 이용 가능하다.users.http
로 생성하고 맞춰서 작성해보았다.
@local=http://localhost:3000
@users=users
### POST /users
POST {{local}}/{{users}} HTTP/1.1
### GET /users
GET {{local}}/{{users}} HTTP/1.1
### GET /users/1
GET {{local}}/{{users}}/1 HTTP/1.1
### PATCH /users/1
PATCH {{local}}/{{users}}/1 HTTP/1.1
### DELETE /users/1
DELETE {{local}}/{{users}}/1 HTTP/1.1
각각 실행해보면 POST
의 성공 응답이 201, 나머지가 200으로 오는게 보이는데,
다른 숫자로 응답하게 수정하고 싶다면 해당 컨트롤러 부분에가서users.controller.ts
파일
import { HttpCode } from '@nestjs/common';
@HttpCode(200)
@Post()
이렇게 데코레이터 선언으로 수정이 가능하다.
요청을 처리 도중 예외를 던저야 한다면 어떻게 해야할까?users.controller.ts
파일
@Get(':id')
findOne(@Param('id') id: string) {
if (+id < 1) {
throw new BadRequestException('id는 0보다 커야 합니다.');
}
return this.usersService.findOne(+id);
}
이렇게 id가 1보다 작은 값이 전달될 경우 400 에러를 던질 수 있다.Tip.
Nest는 string, number, boolean 등 자바스크립트 원시 타입을 리턴시 직렬화 없이 바로 보내지만, 객체를 리턴한다면 직렬화를 통해 JSON 으로 자동 변환해서 보내준다!
Header 헤더
Nest는 응답시 기본 헤더를 자동으로 구성해서 던져준다.
나만의 헤더를 추가하고 싶다면 @Header
데코레이터를 이용해 쉽게 추가가 가능하다.
import { Header } from '@nestjs/common';
@Header('Custom', 'Test Header')
@Get(':id')
findOneWithHeader(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
Redirection 리다이렉션
클라이언트의 요청을 처리 후 클라이언트를 다른 페이지로 이동시킬 때!@Redirect
데코레이터를 이용해 쉽게 구현이 가능하다.
import { Redirect } from '@nestjs/common';
@Redirect('https://nestjs.com', 301)
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
처리 결과에 따라 동적으로 리다이렉트시 객체에 담아 리턴해도된다.
{
"url": string,
"statusCode": number
}
쿼리 파라미터로 리다이렉트시
ex)버전 숫자를 입력 받아 해당 페이지로 이동시
@Get('redirect/docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' };
}
}
라우트 파라미터
URL 파라미터를 받을 시 아래와 같은 방법으로 받는게 좋다.
@Delete(':userId/memo/:memoId')
deleteUserMemo(
@Param('userId') userId: string,
@Param('memoId') memoId: string,
) {
return `userId: ${userId}, memoId: ${memoId}`;
}
Sub-Domain Routing 하위 도메인 라우팅
http://localhost
, http://api.localhost
로 각각 들어온 요청을 서로 다르게 처리하고, 하위 도메인에서 처리하지 못하는 요청은 원래 도메인에서 처리하는 방법!
우선 컨트롤러를 생성해보자nest g co Api
우리는 ApiController가 먼저 처리될 수 있도록할 것이다.app.module.ts
파일에서 AppController
와 ApiController
의 순서를 바꿔주자.api.controller.ts
파일로가서
@Controller({ host: 'api.localhost' })
export class ApiController {
@Get()
index(): string {
return 'Hello, API';
}
}
와 같이 수정을하면 해당 url로 들어온 모든 요청들은 저기로 빠지게된다.
로컬 curl 테스트 오류는Linux
: /etc/hosts
에서Windows
: C:\Windows\System32\drivers\etc\hosts
에서
...
127.0.0.1 api.localhost
127.0.0.1 v1.api.localhost
로 수정하면된다.
앞에서 배운 url 파라미터를 @Param 데코레이터로 받는 것처럼
여기서도 @HostParam 데코레이터를 이용해 서브 도메인을 변수로 받을 수 있다.
ex)버전별로 API 도메인 분리
@Controller({ host: ':version.api.localhost' })
export class ApiController {
@Get()
index(@HostParam('version') version: string): string {
return `Hello, API ${version}`;
}
}
Payload 다루기
POST, PUT, PATCH 요청은 처리에 필요한 데이터를 함께 보낸다.
NestJS에서는 이걸 스프링에서처럼 DTO에 정의해서 쉽게 다룰 수 있다.
(잠깐! DTO & VO 차이는 VO에서는 getter 기능만 존재!)
ex) 회원가입시 이름과 이메일을 받는다고 가정.create-user.dto.ts
파일
export class CreateUserDto {
name: string;
email: string;
}
users.controller.ts
파일
@Post()
create(@Body() createUserDto: CreateUserDto) {
const { name, email } = createUserDto;
return `유저를 생성했습니다. 이름: ${name}, 이메일: ${email}`;
}
GET 방식으로 url 파라미터를 통해 유저 목록을 가져오는 경우GET /users?offset=0&limit=10
처럼 페이징 옵션을 받을 수 있는데
이럴 경우 GET용 DTO를 따로 생성하는 것도 가능하다.get-user.dto.ts
파일 생성 후
export class GetUsersDto {
offset: number;
limit: number;
}
참조 : NestJS로 배우는 백엔드 프로그래밍
'[NestJS]' 카테고리의 다른 글
[NestJS] - 6편 (DB연결하기 TypeORM 트랜잭션 마이그레이션) (0) | 2022.04.21 |
---|---|
[NestJS] - 5편 (파이프) (0) | 2022.04.20 |
[NestJS] - 4편 (모듈~config파일) (0) | 2022.04.20 |
[NestJS] - 3편 (프로바이더) (0) | 2022.04.19 |
[NestJS] - 1편 (NestJS란?) (0) | 2022.04.18 |