우선
설치 할 것들이 여러가지가 있는데
구글 검색 창에 insomnia rest를 검색해보자
공짜 버전으로 회원가입을 진행해준다.
내가 생각하기에는 그냥 Postman 과 유사한 API 테스트 프로그램이라고 생각한다.
설치가 완료 되면
이와 같은 파일 리스트를 볼 수 있고
기본 세팅 언어는 TypeScript 입니다.
이와 같이 MVC 모델링을 제공하는 것 같네요
다음으로 Package.json 파일을 확인합니다.
{
"name": "hi-nest",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
npm run start:dev
해당 명령어로 프로젝트를 실행해 봅시다.
실행 완료 !
Nest.js 에는 main.ts 가 있는데 이 파일은 절대로 해당 이름 그대로 유지 되어야 한다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
내부는 그냥 간단한 서버에 올리는 소스 코드 정도 ?
app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
@module -> 데코레이터라고 부른다.
클래스에 함수 기능을 추가할 수 있다 - > Java Bean ? 같은건가 ?
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
해당 소스가 있다.
getHello 함수를 따라 appService로 가면
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
여기서 getHello 함수가 호출 되어 웹 페이지에 반영된다.
여기서 Controller 는 -> node.js 의 라우터 같은 존재 ?
url 을 가져오고 함수를 실행하는 정도
하나 테스트 해보자
@Get('/hello')
sayHello(): string {
return this.appService.sayHello();
}
요렇게 코드를 추가하고 물론 appService 에도 함수를 등록하면
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
sayHello(): string {
return 'fuck you!!';
}
}
url 타고 잘 들어가 질까?
잘 된다.
코드를 체계적으로 구체화 하고 이해하기 쉽게 만들어주는 프레임워크 !
라우터를 따로 세팅 안해줘도 된다.
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('/hello')
sayHello(): string {
return this.appService.sayHello();
}
@Post('/hello')
byeBye(): string {
return this.appService.byeBye();
}
}
그렇다면 그냥 return 에다가 함수를 작성하면되는데 왜 service가 필요할까 ?
Nest.js는 Node.js 환경에서 서버 사이드 애플리케이션을 구축하기 위한 프레임워크입니다. Nest.js의 아키텍처는 모듈성, 확장성, 유지보수성을 강조하며, 다음과 같은 주요 컴포넌트로 구성됩니다.
모듈 (Modules):
Nest.js 애플리케이션은 모듈로 구성됩니다.
모듈은 관련된 기능을 캡슐화하고 구성하는 데 사용됩니다.
각 모듈은 컨트롤러, 프로바이더, 서비스 등을 포함할 수 있습니다.
모듈은 @Module 데코레이터를 사용하여 정의됩니다.
컨트롤러 (Controllers):
컨트롤러는 들어오는 HTTP 요청을 처리하고 응답을 반환하는 역할을 합니다.
@Controller 데코레이터를 사용하여 컨트롤러를 정의합니다.
컨트롤러는 라우트 핸들러 메서드를 포함하며, HTTP 메서드에 해당하는 데코레이터(@Get, @Post 등)를 사용하여 정의합니다.
프로바이더와 서비스 (Providers and Services):
프로바이더는 Nest.js의 종속성 주입 시스템에서 사용되는 객체입니다.
서비스는 애플리케이션의 비즈니스 로직을 캡슐화하고 재사용 가능한 코드를 제공하는 프로바이더의 한 유형입니다.
@Injectable 데코레이터를 사용하여 프로바이더와 서비스를 정의합니다.
프로바이더와 서비스는 종속성 주입을 통해 다른 컴포넌트에 주입될 수 있습니다.
종속성 주입 (Dependency Injection):
Nest.js는 강력한 종속성 주입 시스템을 제공합니다.
종속성 주입을 통해 객체 간의 느슨한 결합을 유지하고 코드의 모듈성과 테스트 가능성을 향상시킵니다.
생성자 주입, 속성 주입, 메서드 주입 등의 방법을 지원합니다.
미들웨어 (Middleware):
미들웨어는 요청과 응답 사이에 위치하여 추가적인 처리를 수행하는 함수입니다.
Nest.js는 Express.js 스타일의 미들웨어를 지원합니다.
미들웨어는 요청 검증, 인증, 로깅 등의 공통 기능을 구현하는 데 사용될 수 있습니다.
예외 필터 (Exception Filters):
예외 필터는 애플리케이션에서 발생하는 예외를 처리하고 적절한 응답을 반환하는 역할을 합니다.
@Catch 데코레이터를 사용하여 예외 필터를 정의합니다.
예외 필터는 특정 예외 클래스나 HTTP 상태 코드에 따라 예외를 처리할 수 있습니다.
파이프 (Pipes):
파이프는 요청 데이터의 유효성 검사, 변환, 필터링 등을 수행하는 데 사용됩니다.
@UsePipes 데코레이터를 사용하여 파이프를 적용할 수 있습니다.
Nest.js는 기본 제공되는 파이프와 사용자 정의 파이프를 지원합니다.
가드 (Guards):
가드는 라우트 핸들러 메서드 실행 전에 인증, 권한 부여 등의 조건을 검사하는 데 사용됩니다.
@UseGuards 데코레이터를 사용하여 가드를 적용할 수 있습니다.
가드는 true/false를 반환하여 요청의 진행 여부를 결정합니다.
인터셉터 (Interceptors):
인터셉터는 요청과 응답을 가로채서 추가적인 처리를 수행하는 역할을 합니다.
@UseInterceptors 데코레이터를 사용하여 인터셉터를 적용할 수 있습니다.
인터셉터는 요청/응답 데이터의 변환, 로깅, 캐싱 등의 기능을 구현하는 데 사용될 수 있습니다.
이러한 컴포넌트들을 조합하여 Nest.js 애플리케이션을 구축할 수 있습니다. Nest.js의 아키텍처는 모듈성과 재사용성을 강조하며, 코드의 구조화와 유지보수성을 향상시킵니다. 또한, TypeScript와 데코레이터를 적극 활용하여 개발 생산성을 높이고 코드의 가독성을 향상시킵니다.
+-----------+
| Module |
+-----------+
| |
+-------+ +-------+
| |
+------+------+ +------+------+
| Controller | | Service |
+-------------+ +-------------+
| | | |
| - Route | | - Business |
| - Handler | | Logic |
| | | |
+-------------+ +-------------+
| |
| |
+------+------+ +------+------+
| Middleware | | Repository |
+-------------+ +-------------+
| | | |
| - Request | | - Data |
| - Response | | Access |
| | | |
+-------------+ +-------------+
다이어그램은 Nest.js 아키텍처의 주요 구성 요소와 그들 간의 관계를 보여줍니다.
Module: 애플리케이션의 기능을 캡슐화하고 구성하는 역할을 합니다.
Controller: HTTP 요청을 처리하고 응답을 반환합니다.
Service: 비즈니스 로직을 구현하고 데이터 액세스를 담당합니다.
Middleware: 요청과 응답 사이에서 추가적인 처리를 수행합니다.
Repository: 데이터베이스와의 상호작용을 추상화하고 데이터 액세스 로직을 캡슐화합니다.
이 다이어그램은 Nest.js 아키텍처의 기본 구조를 나타내며, 실제 애플리케이션에서는 더 많은 컴포넌트와 레이어가 포함될 수 있습니다.
터미널에 nest 라는 명령어를 치면
해당 명령어를 통해 쉽게 원하는 컴포넌트를 만들 수 있다 .
예를 들어 nest g co
바로 생성된다.
module 파일에도 자동으로 등록 된다.
import { Module } from '@nestjs/common';
import { MoviesController } from './movies/movies.controller';
@Module({
imports: [],
controllers: [MoviesController],
providers: [],
})
export class AppModule {}
import { Controller, Get } from '@nestjs/common';
@Controller('movies')
export class MoviesController {
@Get()
getAll(): string {
return 'this will return all movies';
}
}
이렇게 컨트롤러에 api 를 작성하면
과연 어떻게 될까?
이렇게 밖에 안나오는데 ...
이게 왜 이런고 하니
Controller에 특정 이름을 붙여주면 그게 url 로 적용이된다.
라익 디스
요부분이 우리 url 의 Entry Point( 엔트리 포인트)를 컨트롤한다는 거지
api 테스터로 확인 해보자
console 에 잘 찍히는 걸 볼 수 있다.
Patch 도 좀 더 수정해보자
@Patch('/:id')
patch(@Param('id') movieId: string, @Body() movieData: any) {
return {
updatedMovie: movieId,
...movieData,
};
}
Patch 부분도 잘 정상작동된다.
보면 express.js 였다면 JSON 을 주고 받을 때 형변환?
코드 적으로 세팅을 해줬어야 한다면
Nest.js 에서는 그냥 보내면 알아서 받는다.
너무 편하다
queryParam 을 보내는 API 를 하나 만들어 보자
// express.js or nest.js 둘다 get : id 보다 다른 get 이 위에 있어야 한다.
@Get('search')
search(@Query("year") searchingYear:string) {
return `We are searching for a movie made after : ${searchingYear}`;
}
id 보다 아래에 위치하면
search가 id로 오인하는 경우가 있다.
다시 api test
query 인자가 잘 들어온다.
이번에는 nest 명령어로 service도 자동으로 생성해보자
아마 nest g s 이 명령어겠지 ?
계속 terminal 통해서
이렇게 친절하게 뭐가 만들어졌는지 잘 나온다.
import { Module } from '@nestjs/common';
import { MoviesController } from './movies/movies.controller';
import { MoviesService } from './movies/movies.service';
@Module({
imports: [],
controllers: [MoviesController],
providers: [MoviesService],
})
export class AppModule {}
providers 에 자동으로 Service 가 등록이 된다.
해당 service에서는 주로 데이터 베이스와 연동하여 Query 문을 처리했을 것이다.
우선은 entity 를 가라로 작성해보자
movie.entity.ts
export class Movie {
id: number;
title: string;
year: number;
genres: string[];
}
nest.js 의 규칙성을 바탕으로 이름을 작성한다.
그리고 Service에 함수를 작성해준다.
import { Injectable } from '@nestjs/common';
import { Movie } from './entities/movie.entity';
@Injectable()
export class MoviesService {
private movies: Movie[] = [];
getAll(): Movie[] {
return this.movies;
}
getOne(id: string): Movie {
return this.movies.find((movie) => movie.id === +id);
}
deleteOne(id: string): boolean {
this.movies.filter((movie) => movie.id !== +id);
return true;
}
create(movieData) {
this.movies.push({
id: this.movies.length + 1,
...movieData,
});
}
}
Controller
import {
Controller,
Get,
Param,
Post,
Delete,
Patch,
Body,
Query,
} from '@nestjs/common';
import { MoviesService } from './movies.service';
import { Movie } from './entities/movie.entity';
@Controller('movies')
export class MoviesController {
//////////////////////////////
// constructor 사용 //
constructor(private readonly moviesService: MoviesService) {}
@Get()
getAll(): Movie[] {
return this.moviesService.getAll();
}
// express.js or nest.js 둘다 get : id 보다 다른 get 이 위에 있어야 한다.
@Get('search')
search(@Query('year') searchingYear: string) {
return `We are searching for a movie made after : ${searchingYear}`;
}
@Get('/:id')
getOne(@Param('id') movieId: string): Movie {
return this.moviesService.getOne(movieId);
}
@Post()
create(@Body() movieData: any) {
return this.moviesService.create(movieData);
}
@Delete('/:id')
remove(@Param('id') movieId: string) {
return this.moviesService.deleteOne(movieId);
}
@Patch('/:id')
patch(@Param('id') movieId: string, @Body() movieData: any) {
return {
updatedMovie: movieId,
...movieData,
};
}
}
이와 같이 작성해주고 다시 테스트 해본다.
'Web Dev > Javascript' 카테고리의 다른 글
Nest.js 데코레이션으로 DTO (Data Transfer Object) 유효성 구성하는 방법 (0) | 2024.05.14 |
---|---|
@nestjs/mapped-types 사용 방법 (0) | 2024.04.25 |
Nest.js의 내장된 코드 테스트 기능 ! Jest 로 하는 유닛테스트 , e2e 테스트 (0) | 2024.04.24 |
[Javascript] 자바스크립트에서 Textarea 값 읽어오기 쉽지만 까먹죠 ! (3) | 2023.12.05 |
jQuery로 특정 <dive> 태그 위치 이동 하기 prependTo 함수 사용법 (0) | 2023.11.15 |
Turing IT 헤드헌터 코딩 테스트 문제 (4) | 2023.11.01 |