์ฒซ๊ฑธ์
์ด ์ผ๋ จ์ ๊ธ์์๋ Nest์ ํต์ฌ ๊ธฐ์ด ๊ฐ๋ ๋ค์ ํ์ตํ๊ฒ ๋ฉ๋๋ค. Nest ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ ๊ตฌ์ฑ ์์์ ์ต์ํด์ง๊ธฐ ์ํด, ์ฐ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ธ CRUD ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๋ณด๋ฉฐ ์ ๋ฌธ ์์ค์์ ๋์ ๋ฒ์๋ฅผ ๋ค๋ฃจ๋ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ ๊ตฌํํด ๋ณผ ๊ฒ์ ๋๋ค.
์ธ์ด
์ฐ๋ฆฌ๋ TypeScript๋ฅผ ์ฌ๋ํ์ง๋ง, ๊ทธ ๋ฌด์๋ณด๋ค๋ Node.js๋ฅผ ์ฌ๋ํฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ Nest๋ TypeScript์ ์์ JavaScript ๋ชจ๋์ ํธํ๋ฉ๋๋ค. Nest๋ ์ต์ ์ธ์ด ๊ธฐ๋ฅ๋ค์ ํ์ฉํ๊ธฐ ๋๋ฌธ์, ์์ JavaScript๋ก ์ฌ์ฉํ๋ ค๋ฉด Babel ์ปดํ์ผ๋ฌ๊ฐ ํ์ํฉ๋๋ค.
์์ ์์๋ ๋๋ถ๋ถ TypeScript๋ฅผ ์ฌ์ฉํ์ง๋ง, ์ธ์ ๋ ์ง ์ฝ๋ ์ค๋ํซ ์ค๋ฅธ์ชฝ ์๋จ์ ์ธ์ด ์ ํ ๋ฒํผ์ ํด๋ฆญํ์ฌ ์์ JavaScript ๋ฌธ๋ฒ์ผ๋ก ๋ฐ๊ฟ๋ณผ ์ ์์ต๋๋ค.
์ฌ์ ์๊ตฌ์ฌํญ
์ด์ ์ฒด์ ์ Node.js (๋ฒ์ 20 ์ด์)๊ฐ ์ค์น๋์ด ์๋์ง ๋ฐ๋์ ํ์ธํ์ธ์.
์ค์
Nest CLI๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํ๋ก์ ํธ ์ค์ ์ด ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. npm์ด ์ค์น๋์ด ์๋ค๋ฉด, ์ด์ ์ฒด์ ์ ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด Nest ํ๋ก์ ํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค:
$ npm i -g @nestjs/cli
$ nest new project-name
ํํธ
๋ณด๋ค ์๊ฒฉํ ๊ธฐ๋ฅ ์ธํธ๋ก ์๋ก์ด TypeScript ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ ค๋ฉด nest new ๋ช ๋ น์ด์ --f ํ๋๊ทธ๋ฅผ ์ถ๊ฐํ์ธ์.
project-name ๋๋ ํฐ๋ฆฌ๊ฐ ์์ฑ๋๊ณ , node_modules ๋ฐ ๋ช ๊ฐ์ง ๋ณด์ผ๋ฌํ๋ ์ดํธ ํ์ผ๋ค์ด ์ค์น๋๋ฉฐ, src/ ๋๋ ํฐ๋ฆฌ๊ฐ ์์ฑ๋์ด ์ฌ๋ฌ ํต์ฌ ํ์ผ๋ค๋ก ์ฑ์์ง๋๋ค.
src/
โโโ app.controller.spec.ts
โโโ app.controller.ts
โโโ app.module.ts
โโโ app.service.ts
โโโ main.ts
๋ค์์ ์ด๋ฌํ ํต์ฌ ํ์ผ๋ค์ ๋ํ ๊ฐ๋ตํ ์ค๋ช ์ ๋๋ค:
app.controller.ts | ๋จ์ผ ๋ผ์ฐํธ๋ฅผ ๊ฐ์ง ๊ธฐ๋ณธ ์ปจํธ๋กค๋ฌ์ ๋๋ค. |
app.controller.spec.ts | ํด๋น ์ปจํธ๋กค๋ฌ์ ๋จ์ ํ ์คํธ์ ๋๋ค. |
app.module.ts | ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฃจํธ ๋ชจ๋์ ๋๋ค. |
app.service.ts | ๋จ์ผ ๋ฉ์๋๋ฅผ ๊ฐ์ง ๊ธฐ๋ณธ ์๋น์ค์ ๋๋ค. |
main.ts | Nest ์ ํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ธฐ ์ํด ํต์ฌ ํจ์์ธ NestFactory๋ฅผ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ง์ ํ์ผ์ ๋๋ค. |
main.ts์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ถํธ์คํธ๋ฉํ๋ ๋น๋๊ธฐ ํจ์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
Nest ์ ํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ธฐ ์ํด, NestFactory๋ผ๋ Nest์ ํต์ฌ ํด๋์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค. NestFactory๋ ์ ํ๋ฆฌ์ผ์ด์ ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์๋ ๋ช ๊ฐ์ง ์ ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ์ค create() ๋ฉ์๋๋ INestApplication ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๊ฐ์ฒด๋ ์ดํ ์ฅ๋ค์์ ์ค๋ช ๋ ๋ค์ํ ๋ฉ์๋๋ค์ ์ ๊ณตํฉ๋๋ค. ์์ main.ts ์์ ์์๋ ๊ฐ๋จํ HTTP ๋ฆฌ์ค๋๋ฅผ ์์ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค์ด์ค๋ HTTP ์์ฒญ์ ๋๊ธฐํ ์ ์๋๋ก ํฉ๋๋ค.
์ฐธ๊ณ ๋ก, Nest CLI๋ก ์ค์บํด๋ฉ ๋ ํ๋ก์ ํธ๋ ๊ฐ ๋ชจ๋์ ์ ์ฉ ๋๋ ํฐ๋ฆฌ์ ๋ณด๊ดํ๋ ๊ด๋ก๋ฅผ ๋ฐ๋ฅด๋๋ก ์ด๊ธฐ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ์์ฑํฉ๋๋ค.
ํํธ
๊ธฐ๋ณธ์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด, ์ฑ์ ์ข ๋ฃ ์ฝ๋ 1๊ณผ ํจ๊ป ์ข ๋ฃ๋ฉ๋๋ค. ๋์ ์ค๋ฅ๋ฅผ throw ํ๋๋ก ํ๋ ค๋ฉด abortOnError ์ต์ ์ ๋นํ์ฑํํ๋ฉด ๋ฉ๋๋ค (์: NestFactory.create(AppModule, { abortOnError: false })).
ํ๋ซํผ
Nest๋ ํ๋ซํผ์ ๊ตฌ์ ๋ฐ์ง ์๋ ํ๋ ์์ํฌ๋ฅผ ์งํฅํฉ๋๋ค. ํ๋ซํผ ๋ ๋ฆฝ์ฑ ๋๋ถ์, ๊ฐ๋ฐ์๋ ๋ค์ํ ์ข ๋ฅ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ ผ๋ฆฌ ๊ตฌ์ฑ ์์๋ค์ ๋ง๋ค๊ณ ํ์ฉํ ์ ์์ต๋๋ค. ๊ธฐ์ ์ ์ผ๋ก Nest๋ ์ด๋ํฐ๊ฐ ์ ๊ณต๋๋ฉด ์ด๋ค Node HTTP ํ๋ ์์ํฌ์๋ ์๋ํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์๋๋ ๋ ๊ฐ์ง HTTP ํ๋ซํผ์ express์ fastify์ด๋ฉฐ, ํ์์ ๋ฐ๋ผ ์ ํฉํ ๊ฒ์ ์ ํํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
platform-express | Express๋ Node๋ฅผ ์ํ ์ ์๋ ค์ง ๋ฏธ๋๋ฉ๋ฆฌ์คํธ ์น ํ๋ ์์ํฌ์ ๋๋ค. ์ปค๋ฎค๋ํฐ์ ์ํด ๋ค์์ ๋ฆฌ์์ค๊ฐ ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ์ค์ ์์ ๊ฒ์ฆ๋ ํ๋ก๋์ ์ค๋น ์๋ฃ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ @nestjs/platform-express ํจํค์ง๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋ง์ ์ฌ์ฉ์๋ค์ Express๋ง์ผ๋ก๋ ์ถฉ๋ถํ ๋ง์กฑํ ์ ์์ผ๋ฉฐ, ๋ณ๋์ ์ค์ ์์ด ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. |
platform-fastify | Fastify๋ ๋์ ์ฑ๋ฅ๊ณผ ๋ฎ์ ์ค๋ฒํค๋๋ฅผ ์ง๋ ํ๋ ์์ํฌ๋ก, ์ต๋ํ์ ํจ์จ์ฑ๊ณผ ์๋ ์ ๊ณต์ ์ค์ ์ ๋ก๋๋ค. Fastify ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค. |
์ด๋ค ํ๋ซํผ์ ์ฌ์ฉํ๋ , ๊ฐ ํ๋ซํผ์ ๊ณ ์ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๊ฐ๊ฐ NestExpressApplication๊ณผ NestFastifyApplication์ผ๋ก ๋ํ๋ฉ๋๋ค.
์๋ ์์ ์ฒ๋ผ NestFactory.create() ๋ฉ์๋์ ํ์ ์ ์ ๋ฌํ๋ฉด, ๋ฐํ๋ app ๊ฐ์ฒด๋ ํด๋น ํ๋ซํผ์๋ง ์กด์ฌํ๋ ์ ์ฉ ๋ฉ์๋๋ค์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. ๋ค๋ง, ์ค์ ๋ก ํ๋ซํผ์ ํ์ API์ ์ ๊ทผํ ํ์๊ฐ ์๋ค๋ฉด ํ์ ์ ๋ช ์ํ ํ์๋ ์์ต๋๋ค.
const app = await NestFactory.create<NestExpressApplication>(AppModule);
์ ํ๋ฆฌ์ผ์ด์ ์คํ
์ค์น ๊ณผ์ ์ด ์๋ฃ๋๋ฉด, ์ด์ ์ฒด์ ์ ๋ช ๋ น ํ๋กฌํํธ์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด HTTP ์์ฒญ์ ์์ ํ๋๋ก ์์ํ ์ ์์ต๋๋ค:
$ npm run start
ํํธ
๊ฐ๋ฐ ์๋๋ฅผ ์ฝ 20๋ฐฐ ๋น ๋ฅด๊ฒ ํ๋ ค๋ฉด, -b swc ํ๋๊ทธ๋ฅผ start ์คํฌ๋ฆฝํธ์ ์ ๋ฌํ์ฌ SWC ๋น๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์:
npm run start -- -b swc
์ด ๋ช ๋ น์ด๋ src/main.ts ํ์ผ์ ์ ์๋ ํฌํธ์์ HTTP ์๋ฒ๋ฅผ ์์ํฉ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๋ฉด ๋ธ๋ผ์ฐ์ ๋ฅผ ์ด๊ณ http://localhost:3000/์ผ๋ก ์ด๋ํ์ธ์. “Hello World!” ๋ฉ์์ง๋ฅผ ๋ณผ ์ ์์ด์ผ ํฉ๋๋ค.
ํ์ผ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ์งํ๋ฉด์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
$ npm run start:dev
์ด ๋ช ๋ น์ด๋ ํ์ผ์ ๊ฐ์ํ๋ฉด์ ์๋์ผ๋ก ๋ค์ ์ปดํ์ผํ๊ณ ์๋ฒ๋ฅผ ์ฌ์์ํฉ๋๋ค.
๋ฆฐํธ์ ํฌ๋งทํ
CLI๋ ๋๊ท๋ชจ ๊ฐ๋ฐ์์๋ ์ ๋ขฐํ ์ ์๋ ์ํฌํ๋ก์ฐ๋ฅผ ์ค์บํด๋ฉ ํ๊ธฐ ์ํด ์ต์ ์ ๋คํฉ๋๋ค. ๋ฐ๋ผ์ ์์ฑ๋ Nest ํ๋ก์ ํธ์๋ ์ฝ๋ ๋ฆฐํฐ์ ํฌ๋งคํฐ๊ฐ ๊ธฐ๋ณธ์ผ๋ก ์ค์น๋์ด ์์ต๋๋ค(๊ฐ๊ฐ eslint์ prettier).
ํํธ
ํฌ๋งคํฐ์ ๋ฆฐํฐ์ ์ฐจ์ด์ ์ด ๊ถ๊ธํ๋ค๋ฉด ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์ต๋์ ์์ ์ฑ๊ณผ ํ์ฅ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด, ์ฐ๋ฆฌ๋ ๊ธฐ๋ณธ eslint ๋ฐ prettier CLI ํจํค์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด ๊ตฌ์ฑ์ ๊ณต์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ํตํ ๊น๋ํ IDE ํตํฉ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
IDE๊ฐ ํ์ํ์ง ์์ ํค๋๋ฆฌ์ค ํ๊ฒฝ(CI, Git hooks ๋ฑ)์์๋ ์ฌ์ฉํ ์ ์๋๋ก Nest ํ๋ก์ ํธ์๋ ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅํ npm ์คํฌ๋ฆฝํธ๊ฐ ํจ๊ป ์ ๊ณต๋ฉ๋๋ค.
# eslint๋ก ๋ฆฐํธ ๋ฐ ์๋ ์์
$ npm run lint
# prettier๋ก ํฌ๋งทํ
$ npm run format
์ปจํธ๋กค๋ฌ
์ปจํธ๋กค๋ฌ๋ ๋ค์ด์ค๋ ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ต์ ๋ฐํํ๋ ์ญํ ์ ํฉ๋๋ค.
์ปจํธ๋กค๋ฌ์ ๋ชฉ์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋๋ค. ๋ผ์ฐํ ๋ฉ์ปค๋์ฆ์ ๊ฐ ์์ฒญ์ ์ด๋ค ์ปจํธ๋กค๋ฌ๊ฐ ์ฒ๋ฆฌํ ์ง๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํ๋์ ์ปจํธ๋กค๋ฌ๋ ์ฌ๋ฌ ๊ฐ์ ๋ผ์ฐํธ๋ฅผ ๊ฐ์ง๋ฉฐ, ๊ฐ ๋ผ์ฐํธ๋ ์๋ก ๋ค๋ฅธ ๋์์ ์ํํ ์ ์์ต๋๋ค.
๊ธฐ๋ณธ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ๋ ค๋ฉด ํด๋์ค์ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ฝ๋ ์ดํฐ๋ ํด๋์ค์ ํ์ํ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ฒฐํ์ฌ, Nest๊ฐ ์์ฒญ๊ณผ ํด๋น ์ปจํธ๋กค๋ฌ๋ฅผ ์ฐ๊ฒฐํ๋ ๋ผ์ฐํ ๋งต์ ์์ฑํ ์ ์๋๋ก ํฉ๋๋ค.
ํํธ
๋ด์ฅ๋ ์ ํจ์ฑ ๊ฒ์ฌ ๊ธฐ๋ฅ๊ณผ ํจ๊ป CRUD ์ปจํธ๋กค๋ฌ๋ฅผ ๋น ๋ฅด๊ฒ ์์ฑํ๋ ค๋ฉด CLI์ CRUD ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค: nest g resource [name]
๋ผ์ฐํ
๋ค์ ์์ ์์๋ ๊ธฐ๋ณธ ์ปจํธ๋กค๋ฌ๋ฅผ ์ ์ํ๊ธฐ ์ํด ํ์์ ์ธ @Controller() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ ํ์ ์ผ๋ก cats๋ผ๋ ๊ฒฝ๋ก ์ ๋์ฌ๋ฅผ ์ง์ ํฉ๋๋ค. @Controller() ๋ฐ์ฝ๋ ์ดํฐ์ ๊ฒฝ๋ก ์ ๋์ฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ด๋ จ๋ ๋ผ์ฐํธ๋ค์ ๊ทธ๋ฃนํํ๊ณ ์ค๋ณต ์ฝ๋๋ฅผ ์ค์ด๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ณ ์์ด (cat) ์ํฐํฐ์์ ์ํธ์์ฉ์ ๊ด๋ฆฌํ๋ ๋ผ์ฐํธ๋ค์ /cats ๊ฒฝ๋ก ์๋๋ก ๋ฌถ๊ณ ์ถ๋ค๋ฉด, @Controller('cats')์ ๊ฐ์ด ์ง์ ํ๋ฉด ๋ฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํด๋น ํ์ผ ๋ด์ ๊ฐ ๋ผ์ฐํธ๋ง๋ค /cats๋ฅผ ๋ฐ๋ณตํด์ ์์ฑํ ํ์๊ฐ ์์ต๋๋ค.
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
ํํธ
CLI๋ฅผ ์ฌ์ฉํ์ฌ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ๋ ค๋ฉด, ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ๋ฉด ๋ฉ๋๋ค: nest g controller [main]
@Get() HTTP ์์ฒญ ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ๋ findAll() ๋ฉ์๋ ์์ ์์นํ๋ฉฐ, Nest์๊ฒ ํน์ ์๋ํฌ์ธํธ์ ๋ํ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ผ๊ณ ์ง์ํฉ๋๋ค. ์ด ์๋ํฌ์ธํธ๋ HTTP ์์ฒญ ๋ฉ์๋(GET)์ ๋ผ์ฐํธ ๊ฒฝ๋ก์ ์ํด ์ ์๋ฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ๋ผ์ฐํธ ๊ฒฝ๋ก๋ ๋ฌด์์ผ๊น์? ํธ๋ค๋ฌ์ ๋ผ์ฐํธ ๊ฒฝ๋ก๋ ์ปจํธ๋กค๋ฌ์ ์ ์ธ๋ (์ ํ์ ์ธ) ์ ๋์ฌ์ ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ์ ์ง์ ๋ ๊ฒฝ๋ก๋ฅผ ๊ฒฐํฉํ์ฌ ๊ฒฐ์ ๋ฉ๋๋ค. ํ์ฌ๋ cats ์ ๋์ฌ๊ฐ ์ค์ ๋์ด ์๊ณ , ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ์๋ ๋ณ๋์ ๊ฒฝ๋ก๊ฐ ์ง์ ๋์ด ์์ง ์์ผ๋ฏ๋ก Nest๋ GET /cats ์์ฒญ์ ์ด ํธ๋ค๋ฌ์ ๋งคํํฉ๋๋ค.
์์ ์ธ๊ธํ๋ฏ์ด, ๋ผ์ฐํธ ๊ฒฝ๋ก๋ ์ปจํธ๋กค๋ฌ์ ๊ฒฝ๋ก ์ ๋์ฌ์ ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ์ ์ง์ ๋ ๊ฒฝ๋ก ๋ฌธ์์ด์ ํฉ์ณ์ ๊ตฌ์ฑ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ์ปจํธ๋กค๋ฌ ์ ๋์ฌ๊ฐ cats์ด๊ณ , ๋ฉ์๋ ๋ฐ์ฝ๋ ์ดํฐ๊ฐ @Get('breed') ๋ผ๋ฉด, ์ค์ ๋ผ์ฐํธ๋ GET /cats/breed๊ฐ ๋ฉ๋๋ค.
์ ์์์์ GET ์์ฒญ์ด ํด๋น ์๋ํฌ์ธํธ๋ก ๋ค์ด์ค๋ฉด, Nest๋ ์์ฒญ์ ์ฌ์ฉ์๊ฐ ์ ์ํ findAll() ๋ฉ์๋๋ก ๋ผ์ฐํ ํฉ๋๋ค. ์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์, ๋ฉ์๋ ์ด๋ฆ์ธ findAll์ ์์ ํ ์์๋ก ์ ํ ๊ฒ์ด๋ฉฐ, ๋ผ์ฐํธ๋ฅผ ์ฐ๊ฒฐํ ๋ฉ์๋๋ฅผ ์ ์ธํด์ผ ํ๊ธด ํ์ง๋ง Nest๋ ๊ทธ ์ด๋ฆ ์์ฒด์ ํน๋ณํ ์๋ฏธ๋ฅผ ๋ถ์ฌํ์ง๋ ์๋๋ค๋ ๊ฒ์ ๋๋ค.
์ด ๋ฉ์๋๋ 200 ์ํ ์ฝ๋์ ํจ๊ป ์๋ต์ ๋ฐํํ๊ฒ ๋๋ฉฐ, ์ฌ๊ธฐ์๋ ๋จ์ํ ๋ฌธ์์ด ํ๋๋ฅผ ์๋ตํฉ๋๋ค. ์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋ ๊น์? ์ด๋ฅผ ์ค๋ช ํ๋ ค๋ฉด, Nest๊ฐ ์๋ต์ ์กฐ์ํ๋ ๋ฐ ์ฌ์ฉํ๋ ๋ ๊ฐ์ง ์ต์ ๊ฐ๋ ์ ๋จผ์ ์๊ฐํ ํ์๊ฐ ์์ต๋๋ค.
ํ์ค (๊ถ์ฅ) | Nest์ ๊ธฐ๋ณธ ๋ฐฉ์์์๋ ์์ฒญ ํธ๋ค๋ฌ๊ฐ JavaScript ๊ฐ์ฒด๋ ๋ฐฐ์ด์ ๋ฐํํ ๊ฒฝ์ฐ, ์๋์ผ๋ก JSON์ผ๋ก ์ง๋ ฌํ๋์ด ์๋ต๋ฉ๋๋ค. ๋ฐ๋ฉด, ๋ฌธ์์ด, ์ซ์, ๋ถ๋ฆฌ์ธ๊ณผ ๊ฐ์ JavaScript์ ์์ ํ์
์ ๋ฐํํ ๊ฒฝ์ฐ์๋ Nest๊ฐ ํด๋น ๊ฐ์ ์ง๋ ฌํํ์ง ์๊ณ ๊ทธ๋๋ก ์ ์กํฉ๋๋ค. ์ด ๋ฐฉ์ ๋๋ถ์ ์๋ต ์ฒ๋ฆฌ ๋ก์ง์ด ๋งค์ฐ ๋จ์ํด์ง๋ฉฐ, ๊ฐ์ ๊ทธ๋๋ก ๋ฐํํ๊ธฐ๋ง ํ๋ฉด ๋๋จธ์ง๋ Nest๊ฐ ์ฒ๋ฆฌํด์ค๋๋ค. ๋ํ, ์๋ต์ ์ํ ์ฝ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํญ์ 200์ด๋ฉฐ, POST ์์ฒญ์ ๊ฒฝ์ฐ์๋ 201์ ์ฌ์ฉํฉ๋๋ค. ์ด ๋์์ ํธ๋ค๋ฌ ์์ค์์ @HttpCode(...) ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค (์์ธํ ๋ด์ฉ์ "Status codes" ์ฐธ๊ณ ) |
๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ๋ฐฉ์ | Express์ ๊ฐ์ ํน์ HTTP ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ง์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๋ฅผ ์ํด์๋ ํธ๋ค๋ฌ์ ์ธ์๋ก @Res() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํด ์๋ต ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ๋ฉด ๋ฉ๋๋ค(์: findAll(@Res() response)). ์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ์๋ต ๋ฉ์๋๋ค์ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Express์์๋ response.status(200).send() ๊ฐ์ ์ฝ๋๋ฅผ ํตํด ์๋ต์ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. |
์ฃผ์
Nest๋ ํธ๋ค๋ฌ์์ @Res() ๋๋ @Next()๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ๋ฐฉ์(์: Express)์ ์ ํํ ๊ฒ์ผ๋ก ๊ฐ์ฃผํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ํด๋น ๋ผ์ฐํธ์ ๋ํด์๋ ํ์ค ๋ฐฉ์(Standard approach)์ด ์๋์ผ๋ก ๋นํ์ฑํ๋๋ฉฐ, ๋ ์ด์ ์ ์์ ์ผ๋ก ์๋ํ์ง ์์ต๋๋ค.
๋ง์ฝ ๋ ๋ฐฉ์์ ๋์์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด(์: ์๋ต ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ์ฌ ์ฟ ํค๋ ํค๋๋ง ์ค์ ํ๊ณ , ๋๋จธ์ง ์๋ต ์ฒ๋ฆฌ๋ Nest์ ๋งก๊ธฐ๊ณ ์ถ์ ๊ฒฝ์ฐ), @Res({ passthrough: true }) ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ passthrough ์ต์ ์ true๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
์์ฒญ ๊ฐ์ฒด
ํธ๋ค๋ฌ๋ ์ข ์ข ํด๋ผ์ด์ธํธ์ ์์ฒญ ์ธ๋ถ ์ ๋ณด์ ์ ๊ทผํ ํ์๊ฐ ์์ต๋๋ค. Nest๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉํ๋ ํ๋ซํผ(๊ธฐ๋ณธ์ Express)์ ์์ฒญ ๊ฐ์ฒด์ ์ ๊ทผํ ์ ์๋๋ก ์ง์ํฉ๋๋ค. ํธ๋ค๋ฌ์ ์๊ทธ๋์ฒ์ @Req() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ฉด, Nest๊ฐ ์์ฒญ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ์ฌ ์ฌ์ฉํ ์ ์๊ฒ ํด ์ค๋๋ค.
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';
}
}
ํํธ
์ ์์ ์ฒ๋ผ request: Request์ ๊ฐ์ด Express์ ํ์ ์ ๋ณด๋ฅผ ํ์ฉํ๋ ค๋ฉด, @types/express ํจํค์ง๋ฅผ ์ค์นํด์ผ ํฉ๋๋ค.
์์ฒญ ๊ฐ์ฒด๋ HTTP ์์ฒญ์ ๋ํ๋ด๋ฉฐ, ์ฟผ๋ฆฌ ๋ฌธ์์ด, ํ๋ผ๋ฏธํฐ, HTTP ํค๋, ๋ฐ๋ ๋ฑ์ ์์ฑ์ ํฌํจํฉ๋๋ค (์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ ์ฐธ๊ณ ). ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ด๋ฌํ ์์ฑ๋ค์ ์๋์ผ๋ก ์ ๊ทผํ ํ์๋ ์์ต๋๋ค. ๋์ , Nest๋ @Body()๋ @Query()์ ๊ฐ์ ์ ์ฉ ๋ฐ์ฝ๋ ์ดํฐ๋ค์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ์ฌ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ํด์ค๋๋ค. ์๋๋ Nest์์ ์ ๊ณตํ๋ ๋ฐ์ฝ๋ ์ดํฐ๋ค๊ณผ ๊ฐ๊ฐ์ด ๋ํ๋ด๋ ํ๋ซํผ๋ณ ๊ฐ์ฒด๋ค์ ๋ชฉ๋ก์ ๋๋ค.
@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(key?: string) | req.headers / req.headers[name] |
@Ip() | req.ip |
@HostParam() | req.hosts |
๊ธฐ๋ณธ HTTP ํ๋ซํผ (์: Express, Fastify) ๊ฐ์ ํ์ ํธํ์ฑ์ ์ํด, Nest๋ @Res()์ @Response() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค. @Res()๋ ๋จ์ํ @Response()์ ๋ณ์นญ์ด๋ฉฐ, ๋ ๋ค ๊ธฐ๋ณธ ํ๋ซํผ์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ง์ ๋ ธ์ถํฉ๋๋ค. ์ด๋ฅผ ์ฌ์ฉํ ๋๋ ํด๋น ํ๋ซํผ์ ํ์ ์ ๋ณด (์: @types/express)๋ฅผ ํจ๊ป ์ค์นํ์ฌ ํ์ ์ง์์ ์ต๋ํ ํ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. @Res() ๋๋ @Response()๋ฅผ ๋ฉ์๋ ํธ๋ค๋ฌ์ ์ฃผ์ ํ๋ฉด, ํด๋น ํธ๋ค๋ฌ๋ Nest์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ๋ชจ๋ (Library-specific mode)๋ก ์ ํ๋ฉ๋๋ค. ์ด ๊ฒฝ์ฐ ์๋ต ์ฒ๋ฆฌ๋ ๊ฐ๋ฐ์์ ์ฑ ์์ด๋ฉฐ, ๋ฐ๋์ res.json(...), res.send(...) ๋ฑ์ ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ด๋ค ํํ๋ก๋ ์๋ต์ ๋ฐํํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด HTTP ์๋ฒ๋ ์๋ต ์์ด ๋๊ธฐ ์ํ์ ๋น ์ง๊ฒ ๋ฉ๋๋ค.
ํํธ
์ปค์คํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ํด๋น ์ฑํฐ์์ ํ์ธํ ์ ์์ต๋๋ค.
๋ฆฌ์์ค
์์ ์ฐ๋ฆฌ๋ ๊ณ ์์ด (cats) ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ค๋ (GET ๋ผ์ฐํธ) ์๋ํฌ์ธํธ๋ฅผ ์ ์ํ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ์๋ํฌ์ธํธ๋ ํจ๊ป ์ ๊ณตํ๊ณ ์ถ์ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ์ํด POST ํธ๋ค๋ฌ๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค:
import { Controller, Get, Post } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Post()
create(): string {
return 'This action adds a new cat';
}
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
์ด์ฒ๋ผ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. Nest๋ ํ์ค HTTP ๋ฉ์๋์ ๋ํ ๋ฐ์ฝ๋ ์ดํฐ๋ค์ ๋ชจ๋ ์ ๊ณตํฉ๋๋ค: @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), @Head(). ์ถ๊ฐ๋ก, @All()์ ๋ชจ๋ HTTP ๋ฉ์๋๋ฅผ ์ฒ๋ฆฌํ๋ ์๋ํฌ์ธํธ๋ฅผ ์ ์ํ ์ ์๊ฒ ํด ์ค๋๋ค.
๋ผ์ฐํธ ์์ผ๋์นด๋
NestJS๋ ํจํด ๊ธฐ๋ฐ ๋ผ์ฐํธ๋ ์ง์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ฒฝ๋ก์ ๋์์ ๋ชจ๋ ๋ฌธ์ ์กฐํฉ๊ณผ ์ผ์น์ํค๊ธฐ ์ํด ๋ณํ(*)๋ฅผ ์์ผ๋์นด๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ ์์ ์์ findAll() ๋ฉ์๋๋ abcd/๋ก ์์ํ๋ ๋ชจ๋ ๋ผ์ฐํธ์ ๋ํด ์คํ๋ฉ๋๋ค. ๊ทธ ๋ค์ ์ด๋ค ๋ฌธ์๊ฐ ์ค๋ ์๊ด์์ต๋๋ค.
@Get('abcd/*')
findAll() {
return 'This route uses a wildcard';
}
abcd/* ๊ฒฝ๋ก๋ abcd/, abcd/123, abcd/abc ๋ฑ๊ณผ ์ผ์นํฉ๋๋ค. ํ์ดํ(-)๊ณผ ์ (.)์ ๋ฌธ์์ด ๊ธฐ๋ฐ ๊ฒฝ๋ก์์ ๋ฌธ์ ๊ทธ๋๋ก ํด์๋ฉ๋๋ค.
์ด ๋ฐฉ์์ Express์ Fastify ๋ชจ๋์์ ๋์ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ต์ ๋ฒ์ ์ Express(v5)์์๋ ๋ผ์ฐํ ์์คํ ์ด ๋ ์๊ฒฉํด์ก์ต๋๋ค. ์์ Express์์๋ ๊ฒฝ๋ก๋ฅผ ๋์์ํค๊ธฐ ์ํด ๋ช ๋ช ๋ ์์ผ๋์นด๋๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด abcd/*splat๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋๋ฐ, ์ฌ๊ธฐ์ splat์ ๋จ์ํ ์์ผ๋์นด๋ ํ๋ผ๋ฏธํฐ์ ์ด๋ฆ์ผ ๋ฟ์ด๋ฉฐ ํน๋ณํ ์๋ฏธ๋ ์์ต๋๋ค. ์ํ๋ ์ด๋ฆ์ผ๋ก ์ง์ ํ ์ ์์ต๋๋ค. ๋ค๋ง, Nest๋ Express๋ฅผ ์ํ ํธํ์ฑ ๋ ์ด์ด๋ฅผ ์ ๊ณตํ๋ฏ๋ก ์ฌ์ ํ ๋ณํ (*)๋ฅผ ์์ผ๋์นด๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ฒฝ๋ก ์ค๊ฐ์์ ๋ณํ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, Express๋ ๋ช ๋ช ๋ ์์ผ๋์นด๋(e.g., ab{*aplat}cd)๋ฅผ ์๊ตฌํ๋ฉฐ, Fastify๋ ์ด๋ฅผ ์ ํ ์ง์ํ์ง ์์ต๋๋ค.
์ํ ์ฝ๋
์์ ์ธ๊ธํ๋ฏ์ด, ์๋ต์ ๊ธฐ๋ณธ ์ํ ์ฝ๋๋ ํญ์ 200์ด๋ฉฐ, POST ์์ฒญ์ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ๊ฐ์ด 201์ ๋๋ค. ์ด ๋์์ ํธ๋ค๋ฌ ์์ค์์ @HttpCode(...) ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
ํํธ
HttpCode๋ @nestjs/common ํจํค์ง์์ ์ํฌํธ ํ์ธ์.
์ํ ์ฝ๋๊ฐ ๊ณ ์ ์ ์ด์ง ์๊ณ ์ฌ๋ฌ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ์๋ต ๊ฐ์ฒด(@Res()๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ์ )๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ์๋ ์์ธ๋ฅผ ๋์ง ์๋ ์์ต๋๋ค.
์๋ต ํค๋
์ปค์คํ ์๋ต ํค๋๋ฅผ ์ง์ ํ๋ ค๋ฉด @Header() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด res.header()๋ฅผ ์ง์ ํธ์ถํ ์ ์์ต๋๋ค.
@Post()
@Header('Cache-Control', 'no-store')
create() {
return 'This action adds a new cat';
}
ํํธ
Header๋ @nestjs/common ํจํค์ง์์ ์ํฌํธ ํ์ธ์.
๋ฆฌ๋ค์ด๋ ์
์๋ต์ ํน์ URL๋ก ๋ฆฌ๋ค์ด๋ ์ ํ๋ ค๋ฉด @Redirect() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ res.redirect()๋ฅผ ์ง์ ํธ์ถํ ์ ์์ต๋๋ค.
@Redirect()๋ url๊ณผ statusCode ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ผ๋ฉฐ, ๋ ๋ค ์ ํ ์ฌํญ์ ๋๋ค. statusCode๋ฅผ ์๋ตํ๋ฉด ๊ธฐ๋ณธ๊ฐ์ 302 (Found)์ ๋๋ค.
@Get()
@Redirect('https://nestjs.com', 301)
ํํธ
๊ฒฝ์ฐ์ ๋ฐ๋ผ HTTP ์ํ ์ฝ๋๋ ๋ฆฌ๋ค์ด๋ ์ URL์ ๋์ ์ผ๋ก ๊ฒฐ์ ํ๊ณ ์ถ์ ์ ์์ต๋๋ค. ์ด๋ด ๋ @nestjs/common์ HttpRedirectResponse ์ธํฐํ์ด์ค๋ฅผ ๋ฐ๋ฅด๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉด ๋ฉ๋๋ค.
๋ฐํ๋ ๊ฐ์ @Redirect() ๋ฐ์ฝ๋ ์ดํฐ์ ์ ๋ฌ๋ ๋ชจ๋ ์ธ์๋ฅผ ๋ฎ์ด์๋๋ค. ์๋ฅผ ๋ค์ด:
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' };
}
}
๋ผ์ฐํธ ํ๋ผ๋ฏธํฐ
์ ์ ์ธ ๊ฒฝ๋ก๋ก๋ ์์ฒญ์ ์ผ๋ถ๋ก ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ผ ํ ๊ฒฝ์ฐ (์: GET /cats/1์์ id๊ฐ 1์ธ ๊ณ ์์ด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ) ์ํ๋ ๋์์ ํ ์ ์์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์๋ ๊ฒฝ๋ก์ ๋ผ์ฐํธ ํ๋ผ๋ฏธํฐ ํ ํฐ์ ์ถ๊ฐํ์ฌ URL์์ ๋์ ๊ฐ์ ์ถ์ถํ ์ ์์ต๋๋ค. ์๋ @Get() ๋ฐ์ฝ๋ ์ดํฐ ์์ ์์์ฒ๋ผ, ๋ผ์ฐํธ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ์ ์๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ ๋ฉ์๋ ์๊ทธ๋์ฒ์ @Param() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ทผํ ์ ์์ต๋๋ค.
ํํธ
ํ๋ผ๋ฏธํฐ๋ฅผ ํฌํจํ ๊ฒฝ๋ก๋ ์ ์ ๊ฒฝ๋ก ๋ค์ ์ ์ธํด์ผ ํฉ๋๋ค. ๊ทธ๋์ผ ํ๋ผ๋ฏธํฐ ๊ฒฝ๋ก๊ฐ ์ ์ ๊ฒฝ๋ก๋ก ํฅํ๋ ํธ๋ํฝ์ ๊ฐ๋ก์ฑ์ง ์๊ฒ ๋ฉ๋๋ค.
@Get(':id')
findOne(@Param() params: any): string {
console.log(params.id);
return `This action returns a #${params.id} cat`;
}
@Param() ๋ฐ์ฝ๋ ์ดํฐ๋ ๋ฉ์๋์ ๋งค๊ฐ๋ณ์ (์ ์์ ์์๋ params)๋ฅผ ๋ฐ์ฝ๋ ์ด์ ํ์ฌ, ๋ผ์ฐํธ ํ๋ผ๋ฏธํฐ๋ค์ ํด๋น ๋งค๊ฐ๋ณ์์ ์์ฑ์ผ๋ก ์ ๊ทผํ ์ ์๊ฒ ํด ์ค๋๋ค. ์ฝ๋์์ ๋ณด์ด๋ฏ์ด, param.id๋ฅผ ์ฐธ์กฐํ์ฌ id ํ๋ผ๋ฏธํฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋๋, ๋ฐ์ฝ๋ ์ดํฐ์ ํน์ ํ๋ผ๋ฏธํฐ ํ ํฐ์ ์ ๋ฌํจ์ผ๋ก์จ, ๋ฉ์๋ ๋ด๋ถ์์ ํด๋น ๋ผ์ฐํธ ํ๋ผ๋ฏธํฐ๋ฅผ ์ด๋ฆ์ผ๋ก ์ง์ ์ฐธ์กฐํ ์๋ ์์ต๋๋ค.
ํํธ
Param์ @nestjs/common ํจํค์ง์์ ์ํฌํธ ํ์ธ์.
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns a #${id} cat`;
}
์๋ธ๋๋ฉ์ธ ๋ผ์ฐํ
@Controller ๋ฐ์ฝ๋ ์ดํฐ๋ host ์ต์ ์ ๋ฐ์ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํด ๋ค์ด์ค๋ HTTP ์์ฒญ์ ํธ์คํธ๊ฐ ํน์ ๊ฐ๊ณผ ์ผ์นํด์ผ๋ง ํด๋น ์ปจํธ๋กค๋ฌ๊ฐ ์ฒ๋ฆฌ๋๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
๊ฒฝ๊ณ
Fastify๋ ์ค์ฒฉ ๋ผ์ฐํฐ (nested routers)๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์, ์๋ธ ๋๋ฉ์ธ ๋ผ์ฐํ ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๊ธฐ๋ณธ Express ์ด๋ํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.
๋ผ์ฐํธ ๊ฒฝ๋ก์ ๋ง์ฐฌ๊ฐ์ง๋ก, host ์ต์ ์์๋ ํ ํฐ์ ์ฌ์ฉํ์ฌ ํธ์คํธ๋ช ๋ด ํน์ ์์น์ ๋์ ๊ฐ์ ์บก์ฒํ ์ ์์ต๋๋ค. ์๋ @Controller() ๋ฐ์ฝ๋ ์ดํฐ ์์ ์ ์๋ ํธ์คํธ ํ๋ผ๋ฏธํฐ ํ ํฐ์ด ์ด๋ฌํ ์ฌ์ฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ์ด๋ ๊ฒ ์ ์ธ๋ ํธ์คํธ ํ๋ผ๋ฏธํฐ๋ ๋ฉ์๋ ์๊ทธ๋์ฒ์ @HostParam() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ถ๊ฐํ์ฌ ์ ๊ทผํ ์ ์์ต๋๋ค.
@Controller({ host: ':account.example.com' })
export class AccountController {
@Get()
getInfo(@HostParam('account') account: string) {
return account;
}
}
์ํ ๊ณต์
๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์จ ๊ฐ๋ฐ์์๊ฒ๋ Nest์์ ๊ฑฐ์ ๋ชจ๋ ๊ฒ์ด ๋ค์ด์ค๋ ์์ฒญ ๊ฐ์ ๊ณต์ ๋๋ค๋ ์ ์ด ๋ค์ ๋๋ผ์ฌ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ํ, ์ ์ญ ์ํ๋ฅผ ๊ฐ์ง ์ฑ๊ธํค ์๋น์ค ๋ฑ๊ณผ ๊ฐ์ ๋ฆฌ์์ค๋ค์ด ํฌํจ๋ฉ๋๋ค. ์ด๋ Node.js๊ฐ ๊ฐ ์์ฒญ์ ๊ฐ๋ณ ์ค๋ ๋๋ก ์ฒ๋ฆฌํ๋ ๋ค์ค ์ค๋ ๋ ๋ฌด์ํ ๋ชจ๋ธ (request/response Multi-Threaded Stateless Model)์ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ, Nest์์ ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํด ์ ํ ๋ฌธ์ ๊ฐ ๋์ง ์์ต๋๋ค.
๊ทธ๋ ๋ค๊ณ ํด๋, ์ผ๋ถ ์์ธ์ ์ธ ๊ฒฝ์ฐ์๋ ์ปจํธ๋กค๋ฌ์ ์์ฒญ ๊ธฐ๋ฐ ์๋ช (request-based lifetime)์ ์ค์ ํด์ผ ํ ํ์๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด GraphQL ์ ํ๋ฆฌ์ผ์ด์ ์์์ ์์ฒญ ๋จ์ ์บ์ฑ, ์์ฒญ ์ถ์ , ๋ฉํฐ ํ๋์ ๊ตฌํ ๋ฑ์ด ์ด์ ํด๋น๋ฉ๋๋ค. ์์กด์ฑ ์ฃผ์ ๋ฒ์ (scope)๋ฅผ ์ ์ดํ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ฌ๊ธฐ์์ ๋ ์์ธํ ์์๋ณผ ์ ์์ต๋๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ
์ฐ๋ฆฌ๋ ํ๋์ ์ธ JavaScript, ํนํ ๋น๋๊ธฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ฃผ๋ชฉํฉ๋๋ค. Nest๊ฐ ๋น๋๊ธฐ ํจ์๋ฅผ ์๋ฒฝํ ์ง์ํ๋ ์ด์ ๋ ๋ฐ๋ก ์ด๊ฒ์ ๋๋ค. ๋ชจ๋ async ํจ์๋ Promise๋ฅผ ๋ฐํํด์ผ ํ๋ฉฐ, ์ด๋ฅผ ํตํด Nest๋ ๋์ค์ ๋ฐํ๋ ๊ฐ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ์๋๋ ๊ทธ ์์์ ๋๋ค:
@Get()
async findAll(): Promise<any[]> {
return [];
}
์ด ์ฝ๋๋ ์์ ํ ์ ํจํฉ๋๋ค. ๊ทธ๋ฌ๋ Nest๋ ํ ๋จ๊ณ ๋ ๋์๊ฐ ๋ผ์ฐํธ ํธ๋ค๋ฌ๊ฐ RxJS์ Observable ์คํธ๋ฆผ์ ๋ฐํํ๋ ๊ฒ๋ ํ์ฉํฉ๋๋ค. Nest๋ ๋ด๋ถ์ ์ผ๋ก ํด๋น ์คํธ๋ฆผ์ ๋ํด ๊ตฌ๋ ์ ์ฒ๋ฆฌํ๊ณ , ์คํธ๋ฆผ์ด ์๋ฃ๋๋ฉด ์ต์ข ์ ์ผ๋ก ๋ฐฉ์ถ๋ ๊ฐ์ ์๋ต์ผ๋ก ๋ฐํํฉ๋๋ค.
@Get()
findAll(): Observable<any[]> {
return of([]);
}
๋ ๋ฐฉ์ ๋ชจ๋ ์ ํจํ๋ฉฐ, ์ํฉ์ ๋ฐ๋ผ ๊ฐ์ฅ ์ ํฉํ ๋ฐฉ์์ ์ ํํ๋ฉด ๋ฉ๋๋ค.
์์ฒญ ๋ณธ๋ฌธ
์ด์ ์์ ์์๋ POST ๋ผ์ฐํธ ํธ๋ค๋ฌ๊ฐ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ ๋ฌ๋ ์ด๋ค ํ๋ผ๋ฏธํฐ๋ ๋ฐ์ง ์์์ต๋๋ค. ์ด์ @Body() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ถ๊ฐํ์ฌ ์ด๋ฅผ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
์งํ์ ์์(TypeScript๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ), DTO(Data Transfer Object) ์คํค๋ง๋ฅผ ์ ์ํด์ผ ํฉ๋๋ค. DTO๋ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๋ฐฉ์์ ์ ์ํ๋ ๊ฐ์ฒด์ ๋๋ค. ์ด DTO ์คํค๋ง๋ TypeScript์ ์ธํฐํ์ด์ค๋ ๋จ์ ํด๋์ค ์ค ํ๋๋ก ์ ์ํ ์ ์์ง๋ง, ์ฌ๊ธฐ์๋ ํด๋์ค ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค. ์์ผ๊น์? ํด๋์ค๋ JavaScript ES6 ํ์ค์ ์ผ๋ถ์ด๊ธฐ ๋๋ฌธ์ ์ปดํ์ผ๋ JavaScript์์๋ ์ค์ ์ํฐํฐ๋ก ์ ์ง๋ฉ๋๋ค. ๋ฐ๋ฉด, ์ธํฐํ์ด์ค๋ ํธ๋์คํ์ผ ์ ์ ๊ฑฐ๋๊ธฐ ๋๋ฌธ์ ๋ฐํ์์์๋ Nest๊ฐ ์ด๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค. ์ด๋ Pipe ๊ธฐ๋ฅ๋ค์ด ๋ฐํ์์์ ๋ณ์์ ๋ฉํํ์ ์ ์ ๊ทผํด์ผ ํ๋ ๊ฒฝ์ฐ์ ๋งค์ฐ ์ค์ํ๋ฉฐ, ํด๋์ค์ผ ๋๋ง ๊ฐ๋ฅํฉ๋๋ค.
์ด์ CreateCatDto ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ด ์๋ค:
export class CreateCatDto {
name: string;
age: number;
breed: string;
}
์ด ํด๋์ค๋ ์ธ ๊ฐ์ง ๊ธฐ๋ณธ ์์ฑ๋ง ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ดํ์๋ ์ด ์๋ก ๋ง๋ DTO๋ฅผ CatsController์์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
@Post()
async create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
ํํธ
Nest์ ValidationPipe๋ ๋ฉ์๋ ํธ๋ค๋ฌ์์ ๋ฐ์์๋ ์ ๋๋ ์์ฑ๋ค์ ํํฐ๋งํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ํ์ฉํ ์์ฑ๋ค์ ํ์ดํธ๋ฆฌ์คํธ๋ก ์ง์ ํ๋ฉด, ํ์ดํธ๋ฆฌ์คํธ์ ํฌํจ๋์ง ์์ ์์ฑ์ ๊ฒฐ๊ณผ ๊ฐ์ฒด์์ ์๋์ผ๋ก ์ ๊ฑฐ๋ฉ๋๋ค. CreateCatDto ์์ ์์๋ name, age, breed ์์ฑ์ด ํ์ดํธ๋ฆฌ์คํธ์ ํด๋นํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค.
์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ
๋ผ์ฐํธ์์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฒ๋ฆฌํ ๋๋ @Query() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ด์ค๋ ์์ฒญ์์ ํด๋น ๊ฐ์ ์ถ์ถํ ์ ์์ต๋๋ค. ์ค์ ๋ก ์ด๋ป๊ฒ ๋์ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์๋ฅผ ๋ค์ด, age์ breed ๊ฐ์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ณ ์์ด ๋ชฉ๋ก์ ํํฐ๋งํ๊ณ ์ ํ๋ ๋ผ์ฐํธ๋ฅผ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. ๋จผ์ , CatsController์์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ํฉ๋๋ค:
@Get()
async findAll(@Query('age') age: number, @Query('breed') breed: string) {
return `This action returns all cats filtered by age: ${age} and breed: ${breed}`;
}
์ด ์์ ์์ @Query() ๋ฐ์ฝ๋ ์ดํฐ๋ ์ฟผ๋ฆฌ ๋ฌธ์์ด์์ age์ breed ๊ฐ์ ์ถ์ถํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์์ฒญ์ ๋ณด๋ธ๋ค๋ฉด:
GET /cats?age=2&breed=Persian
age๋ 2, breed๋ Persian์ผ๋ก ์ค์ ๋ฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์์ ์ค์ฒฉ๋ ๊ฐ์ฒด๋ ๋ฐฐ์ด๊ณผ ๊ฐ์ ๋ณต์กํ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ:
?filter[where][name]=John&filter[where][age]=30
?item[]=1&item[]=2
์ฌ์ฉ ์ค์ธ HTTP ์ด๋ํฐ (Express ๋๋ Fastify)์ ์ ์ ํ ์ฟผ๋ฆฌ ํ์ ์ค์ ์ด ํ์ํฉ๋๋ค. Express์์๋ ํ์ฅ ํ์ (extended parser)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ํ๋ถํ ํํ์ ์ฟผ๋ฆฌ ๊ฐ์ฒด๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.set('query parser', 'extended');
Fastify์์๋, querystringParser ์ต์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({
querystringParser: (str) => qs.parse(str),
}),
);
ํํธ
qs๋ ์ค์ฒฉ ๊ตฌ์กฐ์ ๋ฐฐ์ด์ ์ง์ํ๋ ์ฟผ๋ฆฌ ๋ฌธ์์ด ํ์์ ๋๋ค. npm install qs ๋ช ๋ น์ด๋ก ์ค์นํ ์ ์์ต๋๋ค.
์์ธ ์ฒ๋ฆฌ
์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ (์ฆ, ์์ธ ์ฒ๋ฆฌ)์ ๋ํ ๋ด์ฉ์ ๋ณ๋์ ์ฅ์์ ๋ค๋ฃจ๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค.
์ ์ฒด ๋ฆฌ์์ค ์์
์๋๋ ์ฌ๋ฌ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ๊ธฐ๋ณธ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ๋ ์์ ์ ๋๋ค. ์ด ์ปจํธ๋กค๋ฌ๋ ๋ด๋ถ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ณ ์กฐ์ํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
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๋ ๋ชจ๋ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์์ฑํด ์ฃผ๋ ์ ๋๋ ์ดํฐ(์คํค๋งคํฑ) ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ์๋ ์์ ์ ์ค์ด๊ณ ์ ๋ฐ์ ์ธ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์ํ ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค.
์์ํ๊ธฐ (Getting up and running)
CatsController๋ฅผ ์์ ํ ์ ์ํ๋๋ผ๋, Nest๋ ์ด๋ฅผ ์๋์ผ๋ก ์ธ์ํ๊ฑฐ๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ์์ต๋๋ค.
์ปจํธ๋กค๋ฌ๋ ๋ฐ๋์ ์ด๋ค ๋ชจ๋์ ์ผ๋ถ๋ก ํฌํจ๋์ด์ผ ํ๋ฉฐ, ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ @Module() ๋ฐ์ฝ๋ ์ดํฐ ์์ controllers ๋ฐฐ์ด์ ๋ฑ๋กํด์ผ ํฉ๋๋ค. ํ์ฌ ๋ฃจํธ ๋ชจ๋์ธ AppModule ์ธ์ ๋ค๋ฅธ ๋ชจ๋์ ์ ์ํ์ง ์์์ผ๋ฏ๋ก, CatsController๋ฅผ AppModule์ ๋ฑ๋กํ์ฌ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
@Module({
controllers: [CatsController],
})
export class AppModule {}
Module() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ํด๋์ค์ ์ฐ๊ฒฐํ๊ธฐ ๋๋ฌธ์, ์ด์ Nest๋ ์ด๋ค ์ปจํธ๋กค๋ฌ๋ค์ ๋ง์ดํธํด์ผ ํ๋์ง ์ฝ๊ฒ ํ์ ํ ์ ์์ต๋๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ๋ฐฉ์
์ง๊ธ๊น์ง๋ ์๋ต์ ์ฒ๋ฆฌํ๋ Nest์ ํ์ค ๋ฐฉ์์ ์ดํด๋ณด์์ต๋๋ค. ๋ ๋ค๋ฅธ ๋ฐฉ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ํน์ ์๋ต ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ๋ ค๋ฉด @Res() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ฐจ์ด์ ์ ๊ฐ์กฐํ๊ธฐ ์ํด CatsController๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค:
import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import { Response } from 'express';
@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([]);
}
}
์ด ๋ฐฉ์์ ํค๋ ์กฐ์์ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณ ์ ๊ธฐ๋ฅ ์ ๊ทผ ๋ฑ ์๋ต ๊ฐ์ฒด์ ๋ํ ์์ ํ ์ ์ด๊ถ์ ์ ๊ณตํ์ฌ ๋ ๋์ ์ ์ฐ์ฑ์ ๊ฐ์ง์ง๋ง, ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ด ๋ฐฉ๋ฒ์ ๋ช ํ์ฑ์ด ๋จ์ด์ง๊ณ ๋ช ๊ฐ์ง ๋จ์ ์ ๋๋ฐํฉ๋๋ค. ๊ฐ์ฅ ํฐ ๋จ์ ์ ์ฝ๋๊ฐ ํ๋ซํผ ์ข ์์ ์ด ๋๋ค๋ ์ ์ ๋๋ค. ์ฌ์ฉํ๋ ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฐ๋ผ ์๋ต ๊ฐ์ฒด์ API๊ฐ ๋ฌ๋ผ์ง ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ํ ์๋ต ๊ฐ์ฒด ๋ฑ์ ๋ชจํนํด์ผ ํ๋ฏ๋ก ํ ์คํธ๊ฐ ๋ ๋ณต์กํด์ง ์ ์์ต๋๋ค.
๊ฒ๋ค๊ฐ ์ด ๋ฐฉ์์ ์ฌ์ฉํ ๊ฒฝ์ฐ, @HttpCode(), @Header() ๋ฐ์ฝ๋ ์ดํฐ๋ Interceptor ๋ฑ Nest์ ํ์ค ์๋ต ์ฒ๋ฆฌ ๋ฐฉ์์ ์์กดํ๋ ๊ธฐ๋ฅ๋ค๊ณผ์ ํธํ์ฑ์ด ๋จ์ด์ง๊ฒ ๋ฉ๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด passthrough ์ต์ ์ ํ์ฑํํ ์ ์์ต๋๋ค:
@Get()
findAll(@Res({ passthrough: true }) res: Response) {
res.status(HttpStatus.OK);
return [];
}
์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด, ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์ฟ ํค๋ ํค๋๋ฅผ ์ค์ ํ๋ ๋ฑ ๋ค์ดํฐ๋ธ ์๋ต ๊ฐ์ฒด์ ์ง์ ์ํธ์์ฉํ ์ ์์ผ๋ฉด์๋, ๋๋จธ์ง ์๋ต ์ฒ๋ฆฌ๋ Nest ํ๋ ์์ํฌ์ ๋งก๊ธธ ์ ์์ต๋๋ค.
Reference
'๐ ๊ณต์ ๋ฌธ์ ๋ฒ์ญ > Nest.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Nest.js] Overview - Interceptors, Custom decorators (0) | 2025.07.13 |
---|---|
[Nest.js] Overview - Pipes, Guards (0) | 2025.07.08 |
[Nest.js] Overview - Middleware, Exception filters (2) | 2025.07.07 |
[Nest.js] Overview - Providers, Modules (0) | 2025.07.05 |
[Nest.js] Introduction (0) | 2025.07.04 |