front인 angular에서 nest를 호출하려고 하니 4200번, 3000번 간의 CORS 정책 문제가 발생하였어요.

이를 해결하기 위해 nest를 수정해보도록 합니다.

먼저 패키지 설치를 해줍니다.

$ npm install --save cors

 

app을 시작하는 부분 저는 'main.ts'에요. 이 소스를 추가해줍니다.

app.enableCors();

전체적인 소스는 아래와 같아요.

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule } from '@nestjs/swagger';
import { SwaggerConfig } from './shared/conf/swagger.config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
    }),
  );

  const swaggerUiEndpoint = '/swagger';
  const document = SwaggerModule.createDocument(app, SwaggerConfig);
  SwaggerModule.setup(swaggerUiEndpoint, app, document);
  app.enableCors();
  await app.listen(3000);
}
bootstrap();

소스코드 한 줄이라 아주 간단하네요.

 

프런트에서 호출한 결과 발생했던 에러 대신 access_token이 정상적으로 넘어옵니다.

 

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] Auth Token을 쿠키에 저장하기  (1) 2022.03.25
[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] app.controller 살펴보기  (0) 2022.03.02

email, password를 통해 로그인하여 access token을 생성하고, 생성된 access token으로 사용자 정보를 조회해 보는 것을 해보았어요. 이어서 token을 쿠키에 저장하는 로직을 구현해 보려고 합니다.

 

1. cookie-parser, @types/cookie-parser 설치

먼저 관련 패키지를 다운로드하여 설치합니다.

$ npm install --save cookie-parser
$ npm install --save-dev @types/cookie-parser

 

2. /login 로직 수정

'app.controller.ts'에서 /login 부분을 살펴보면 authSevice의 login을 이용하여 생성된 access_token을 바로 return 해주고 있는데요. 여기서 return 하는 부분을 수정하여 쿠키에 저장하도록 합니다.

async login(
    @Body() user: UserDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    const access_token = await this.authService.login(user);
    res.cookie('Authentication', access_token, {
      domain: 'localhost',
      path: '/',
      httpOnly: true,
    });
    return access_token;
  }

access_token에 생성한 토큰을 저장하고, 이를 쿠키에 저장하도록 수정하였습니다. 전, 후 비교는 아래와 같습니다.

 

3. cookie parser 설정

swagger 사용할 때도 main에서 setup 했던 거 기억나시죠? cookie parser를 사용하기 위해서도 main.ts에서 설정을 해줍니다.

기존에 swagger 설정 했던 부분과 포트 3000 listen 사이에 아래의 코드를 추가해 줍니다.

// cookieyParser
app.use(cookieParser());

 

4. jwt에서 쿠키 사용 설정

그리고 저장된 쿠키를 이용하여 토큰을 확인할 수 있도록 jwtStrategy를 수정합니다.

'jwt.strategy.ts'

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromExtractors([
        (request) => {
          return request?.cookies?.Authorization;
        },
      ]),
      // Request에서 JWT를 추출하는 방법 중 Header에 Bearer Token 사용
      // ExtractJwt.fromAuthHeaderAsBearerToken()
      ignoreExpiration: false, // jwt 보증을 passport 모듈에 위임함. 만료된 JWT인경우 request거부, 401 response
      secretOrKey: jwtConstants.secret, // token 발급에 사용할 시크릿 키
    });
  }

 

5. Postman 테스트하기

기존의 /auth/login을 실행한 결과 Cookies에 (1)이 생겼어요.

확인해 보니 Authentication이 제대로 저장되어 있네요.  

 

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] Angular에서 Nest 호출, CORS 해결  (0) 2022.03.25
[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] app.controller 살펴보기  (0) 2022.03.02

지난번 개발한 부분까지 Postman을 통하여 테스트해보았어요. 이번에는 backend api 테스트 환경에서 많이 쓰이는 swagger를 통해 테스트를 해보도록 합니다.

먼저, 프로젝트에 swagger 설정하는 것 부터 시작해 보겠습니다.

 

1. swagger 설치

$ npm install --save @nestjs/swagger swagger-ui-express

npm을 이용하여 swagger를 설치 합니다.

 

2. swagger 설정

main.ts에서 SwaggerModule을 이용하여 설정해줍니다.

소스코드는 아래와 같은데, SwaggerConfig를 이용하여 SwaggerModule의 도큐먼트를 생성하고 생성한 도큐먼트를 가지고 SwaggerModule을 설정하는 코드입니다.

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule } from '@nestjs/swagger';
import { SwaggerConfig } from './shared/conf/swagger.config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
    }),
  );

  const swaggerUiEndpoint = '/swagger';
  const document = SwaggerModule.createDocument(app, SwaggerConfig);
  SwaggerModule.setup(swaggerUiEndpoint, app, document);

  await app.listen(3000);
}
bootstrap();

swaggerUiEndpoint를 '/swagger'로 하였기에 swagger의 주소는 'http://localhost:3000/swagger/'가 된다.

설정은 너무도 간단하죠? 그럼 SwaggerConfig부분을 살펴보도록 하겠습니다.

Config를 알아야 원하는 설정을 하여 사용할 수 있으니까요!

 

3. swagger  config

'swagger.config.ts'파일을 열어보면 코드가 가시적으로 잘 되어 있는데요. 저는 jwt의 bearer를 사용하기 위해

.addBearerAuth 부분을 수정했습니다.

import { DocumentBuilder } from '@nestjs/swagger';

export const SwaggerConfig = new DocumentBuilder()
  .setTitle('bcheck back auth')
  .setDescription('bcheck backend auth microservice')
  .setVersion('3.0.0')
  // .setHost('localhost:3000')
  //.setBasePath('/')
  // .setSchemes('http')
  .setExternalDoc('For more information', 'http://swagger.io')
  .addTag('Application', 'bcheck-back-auth')
  .addBearerAuth(
    {
      type: 'http',
      scheme: 'bearer',
      name: 'JWT',
      in: 'header',
    },
    'access_token',
  )
  .build();

그리고 swagger에 api들이 보이도록 설정해 보겠습니다.

 

4. api 설정

'app.controller.ts'를 살펴보면 @ApiOperation, @ApiCreatedResponse, @ApiResponse, @ApiBody가 보입니다.

@ApiOperation({
    summary: '사용자 login',
    description: '추후 cognito 연결, usersService에 등록된 사용자 login',
  })
  @ApiCreatedResponse({
    schema: {
      example: {
        access_token:
          'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyRW1haWwiOiJzb3J5NTMzOUBnbWFpbC5jb20iLCJzdWIiOjEsImlhdCI6MTY0NzgyMjQxMCwiZXhwIjoxNjQ3ODIyNDcwfQ.NpWT0a2VxTLPqbl3ZHwqlNYh4Rwwhv0p0WWgUpaY3CE',
      },
    },
  })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @ApiBody({ type: UserDto })
  @UseGuards(LocalAuthGuard)
  @Post('/login')
  async login(@Body() user: UserDto) {
    // return req.user;
    return this.authService.login(user);
  }

@ApiOperation : api에 대한 설명

@ApiCreatedResponse : request 성공했을 때 반환될 response

@ApiResponse : request에 대한 repsonse의 직접 설정

@ApiBody : body로 넘겨줄 형태 지정

각각의 설정을 위와 같이 한 경우 아래의 화면처럼 실행됩니다.

 

 

userEmail, password를 입력하여 access_token이 반환되는 /auth/login api에 대한 swagger가 완성되었습니다.

 

5. Try it out

실제로 테스트를 해보겠습니다. 'Try it out'버튼을 클릭하면 'Request body'부분이 확장됩니다.

해당 부분에 body로 넘겨줄 데이터를 json형태로 입력하고 'Execute'하면 아래에 Responses가 보이게 됩니다.

request에 대한 response가 정상적으로 이루어지는 것을 확인할 수 있어요.

앞으로 만들 api에 대해서도 @데코레이터 잘 달아서 swagger로 테스트할 수 있도록 구현해보겠습니다.

728x90
반응형

MSA(Micro  Software Architecture) 구현 중 사용자 로그인과 관련하여 Authentication 부분을 구현해봅니다.

기존에 nest 개발하기 포스트에 이어서 작업한다고 생각하면 되겠습니다.

https://sound-story.tistory.com/3

 

[NestJS] 개발하기

1. Installation Nest CLI를 통해 쉽게 프로젝트 생성할 수 있다. npm i -g @nestjs/cli npm을 통해 @nestjs/cli를 설치한다. -g 옵션을 통해 글로벌 환경에 설치하였다. 글로벌 환경의 설치 경로를 확인할 수 있..

sound-story.tistory.com

 

먼저 인증과 관련된 모듈 설치를 합니다.

$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local
$ npm install --save @nestjs/jwt passport-jwt

다음으로 사용할 service와 module을 생성합니다.

인증 관련 서비스를 구현할 auth와 사용자 정보를 가지고 있을 users입니다.

저희는 users와 관련된 부분은 별도의 MSA구조로 가져갈 것이기에 users에는 email, password 정도의 간단한 정보만 가지고 있을 예정입니다.

$ nest g module auth
$ nest g service auth
$ nest g module users
$ nest g service users

위와 같이 generate 하면 아래와 같은 소스 구조를 갖게 됩니다.

├── src
│   ├── auth
│   │   ├── auth.module.ts
│   │   ├── auth.service.ts
│   ├── users
│   │   ├── users.module.ts
│   │   ├── users.service.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts

 

users.service.ts를 구현해 보도록 하겠습니다.

추후 AWS Cognito를 연결할 예정이기 때문에 사용자 정보를 임시로 저장하여 구현해 보겠습니다.

사용자 정보는 readonly로 저장이 되어 있고, email 정보로 사용자 정보를 찾는 findOne 메서드를 가지고 있습니다.

import { Injectable } from '@nestjs/common';

export type User = any;

@Injectable()
export class UsersService {
  private readonly users = [
    {
      userId: 1,
      userEmail: 'sory5339@gmail.com',
      password: 'sory5339',
    },
  ];

  async findOne(userEmail: string): Promise<User | undefined> {
    return this.users.find((user) => user.userEmail === userEmail);
  }
}

 

UsersService에 대하여 users.module.ts를 수정합니다.

exports를 하였는데 그 이유는 UsersModule 외 다른 모듈에서도 UsersService를 사용하기 위함입니다.

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';

@Module({
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

 

다음으로 AuthService를 구현해 보도록 하겠습니다. 먼저 nest의 jwt 사용을 위해 설치해줍니다.

$ npm install --save @nestjs/jwt

auth.service.ts를 살펴보면 UsersService와 JwtService를 사용하여 validateUser와 login메서드를 구현했습니다.

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from 'src/users/users.service';

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
  ) {}

  async validateUser(userEmail: string, password: string): Promise<any> {
    const user = await this.usersService.findOne(userEmail);
    if (user && user.password === password) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

  async login(user: any) {
    const payload = { userEmail: user.userEmail, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}
  • validateUser는 사용자의 email, password를 받아와 usersService에 있는 유효한 사용자인지 확인하여 사용자 정보 중 password를 제외한 정보를 result로 return 합니다.
  • login메서드는 사용자의 email과 userId를 payload로 하여 jwtService를 이용하여 token을 생성합니다.

이제 AuthModule을 구현해 봐야겠죠. import부분을 보면 jwtConstants, JwtStrategy, LocalStrategy가 있어요.

Passport strategy를 구현해 봅니다.  auth 폴더에 'local.strategy.ts'파일을 생성하여 아래와 같이 구현해주세요.

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({
      usernameField: 'userEmail',
    });
  }

  async validate(userEmail: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(userEmail, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

constructor내의 super 부분을 보면, 저는 usernameField에 userEmail을 이용하도록 하였습니다.

validate 메서드에서는 email과 password로 user가 아니면 Exception을 user이면 user를 return 해줍니다.

 

다음으로 jwt(jason web token) 구현을 위한 준비입니다. import jwtConstants와 관련된 부분이에요.

auth폴더 아래에 'constants.ts' 파일을 추가하여 아래와 같이 구현합니다. jwt를 생성할 때 사용하는 시크릿 키로 외부에 노출되면 안 되는 부분입니다.

export const jwtConstants = {
  secret: 'secretKey', // token 발급 시 사용되는 시크릿 키. 노출되면 안됨.
};

 

마지막으로 JwtStrategy를 위해 'jwt.strategy'를 생성해줍니다. LocalStrategy처럼  JWT를 위한 PassportStrategy확장형 JwtStrategy입니다.

local에서는 매핑할 filed 정도만 정의해 주었는데 jwt에서는 여러 가지 정보가 있어요. 상세 내용은 주석을 참고하세요.

import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from './constants';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Request에서 JWT를 추출하는 방법 중 Bearer Token 사용
      ignoreExpiration: false, // jwt 보증을 passport 모듈에 위임함. 만료된 JWT인경우 request거부, 401 response
      secretOrKey: jwtConstants.secret, // token 발급에 사용할 시크릿 키
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, userEmail: payload.userEmail };
  }
}

여기까지 import 된 부분에 대한 설명이었고, auth.module의 imports를 보면 UsersModule, PassportModule을 가져왔고 JwtModule은 register를 통해 등록하였어요. register() 안쪽 부분이 JwtModule에 대한 Options이에요.

 

auth module까지 끝났고요. 이제 guards에 대한 부분을 구현해 보도록 하겠습니다.

Guards의 역할은 request가 처리될지 말지를 결정합니다. 예를 들어 로그인에 정상적으로 성공한 경우 이후의 프로세스를 실행할 수 있지만, 로그인에 실패한 경우 더 이상 접근할 수 없도록 하는 것이지요.

 

'app.controllers.ts'를 열어 수정해줍니다. app.으로 왔다니 뭔가 끝이 보이는 거 같네요.

import { Controller, Request, Get, Post, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiParam } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { get } from 'http';
import { AppService } from './app.service';
import { AuthService } from './auth/auth.service';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { LocalAuthGuard } from './auth/local-auth.guard';

@Controller('auth')
export class AppController {
  constructor(
    private authService: AuthService,
    private appService: AppService,
  ) {}
  // @UseGuards(AuthGuard('local'))
  @UseGuards(LocalAuthGuard)
  @Post('/login')
  async login(@Request() req) {
    // return req.user;
    return this.authService.login(req.user);
  }

  @UseGuards(JwtAuthGuard)
  @Get('/profile')
  getProfile(@Request() req) {
    return req.user;
  }

  @Get('/helloworld')
  getHello(): string {
    return this.appService.getHello();
  }
  @Get('/health')
  @ApiOperation({
    summary: 'auth health check',
    description: 'auth application 이 정상 상태인지 체크한다.',
  })
  getHealth(): string {
    return this.appService.getHealth();
  }
}

guard에 대한 부분도 strategy와 같이 local, jwt가 있어요.

먼저 'local-auth.guard.ts'를 구현합니다.

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}

'jwt-auth.guard.ts'

import {
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext) {
    // Add your custom authentication logic here
    // for example, call super.logIn(request) to establish a session.
    return super.canActivate(context);
  }

  handleRequest(err, user, info) {
    // You can throw an exception based on either "info" or "err" arguments
    if (err || !user) {
      throw err || new UnauthorizedException();
    }
    return user;
  }
}

 

이제 코딩은 완료되었습니다. 테스트를 진행해 볼까요.

$ yarn start

서비스는 정상적으로 올라왔네요!

이번에는 Postman을 이용하여 사용자 로그인 정보를 넘겨서 테스트해봅니다.

유효한 사용자 정보를 입력하니 access_token이 정상적으로 생성됩니다.

http://localhost:3000/auth/login

이 토큰을 가지고 profile 정보를 조회해 봅니다.

http://localhost:3000/auth/profile

토큰 정보로 사용자 정보를 가져오는 것까지 확인해 보았습니다.

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] Auth Token을 쿠키에 저장하기  (1) 2022.03.25
[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] app.controller 살펴보기  (0) 2022.03.02
[NestJS] 개발하기  (0) 2022.02.25

nest cli는 많은 기능을 제공하는 데, 그중 generator를 이용하여 CRUD를 구현해 보겠습니다.

먼저 nest -h 명령어를 통해 nest에서 사용하는 alias를 확인해 볼게요.

nest -h
Usage: nest <command> [options]

Options:
  -v, --version                                   Output the current version.
  -h, --help                                      Output usage information.

Commands:
  new|n [options] [name]                          Generate Nest application.
  build [options] [app]                           Build Nest application.
  start [options] [app]                           Run Nest application.
  info|i                                          Display Nest project details.
  update|u [options]                              Update Nest dependencies.
  add [options] <library>                         Adds support for an external library to your project.
  generate|g [options] <schematic> [name] [path]  Generate a Nest element.
    Schematics available on @nestjs/schematics collection:
      ┌───────────────┬─────────────┬──────────────────────────────────────────────┐
      │ name          │ alias       │ description                                  │
      │ application   │ application │ Generate a new application workspace         │
      │ class         │ cl          │ Generate a new class                         │
      │ configuration │ config      │ Generate a CLI configuration file            │
      │ controller    │ co          │ Generate a controller declaration            │
      │ decorator     │ d           │ Generate a custom decorator                  │
      │ filter        │ f           │ Generate a filter declaration                │
      │ gateway       │ ga          │ Generate a gateway declaration               │
      │ guard         │ gu          │ Generate a guard declaration                 │
      │ interceptor   │ in          │ Generate an interceptor declaration          │
      │ interface     │ interface   │ Generate an interface                        │
      │ middleware    │ mi          │ Generate a middleware declaration            │
      │ module        │ mo          │ Generate a module declaration                │
      │ pipe          │ pi          │ Generate a pipe declaration                  │
      │ provider      │ pr          │ Generate a provider declaration              │
      │ resolver      │ r           │ Generate a GraphQL resolver declaration      │
      │ service       │ s           │ Generate a service declaration               │
      │ library       │ lib         │ Generate a new library within a monorepo     │
      │ sub-app       │ app         │ Generate a new application within a monorepo │
      │ resource      │ res         │ Generate a new CRUD resource                 │
      └───────────────┴─────────────┴──────────────────────────────────────────────┘

맨 아래에 보시면 CRUD가 있습니다. resource 또는 res를 이용하면 CRUD에 필요한 템플릿을 만들 수 있습니다.

저는 auth라는 CRUD 기능을 만들어 보겠습니다.

nest g res auth 
? What transport layer do you use? 
> REST API
  GraphQL (code first)
  GraphQL (schema first)
  Microservice (non-HTTP)
  WebSockets
? Would you like to generate CRUD entry points? (Y/n) Y
CREATE src/auth/auth.controller.spec.ts (556 bytes)
CREATE src/auth/auth.controller.ts (883 bytes)  
CREATE src/auth/auth.module.ts (240 bytes)      
CREATE src/auth/auth.service.spec.ts (446 bytes)
CREATE src/auth/auth.service.ts (607 bytes)
CREATE src/auth/dto/create-auth.dto.ts (30 bytes)
CREATE src/auth/dto/update-auth.dto.ts (164 bytes)
CREATE src/auth/entities/auth.entity.ts (21 bytes)
UPDATE src/app.module.ts (388 bytes)

nest g res 명령 실행 시 어떤 전송방법을 사용할지, CRUD point를 생성할지에 대해 물어봅니다.

저는 REST API, Y를 선택하여 생성하였습니다. 이제 start를 해보겠습니다.

 yarn start

"Nest application successfully started" 성공적으로 시작했다고 합니다.

"http://localhost:3000/auth"로 접속해 보니 "Hello" 메시지를 정상적으로 만나볼 수 있습니다.

하지만 우리는 이걸 목적으로 한 것이 아니기에 "http://localhost:3000/auth/1"로 접속해 봅니다.

이렇게 나오게 되면, Resource생성이 정상적으로 완료되었음을 확인할 수 있습니다.

생성된 폴더 구조를 살펴보도록 하겠습니다.

.ts파일 중 spec.ts는 테스트 파일, dto, entities폴더에 있는 파일은 DB와 관련된 파일입니다.

먼저 이외의 controller, moduel, service에 대해서 살펴보겠습니다.

 

> service

service파일은 비즈니스 로직을 처리하는 파일입니다. auth.service.ts의 AuthService를 살펴보면

create, findAll, findOne, update, remove라는 메서드가 있습니다.

방금 전, "http://localhost:3000/auth/1"를 호출하였을 때 만났던 메시지가 findOne 메서드를 통해 response 되었겠네요.

findOne(id: number) {
    return `This action returns a #${id} auth`;
  }

> controller

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post()
  create(@Body() createAuthDto: CreateAuthDto) {
    return this.authService.create(createAuthDto);
  }

  @Get()
  findAll() {
    return this.authService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.authService.findOne(+id);
  }

controller를 살펴보면 @Get, @Post, @Delete, @Patch와@Controller('auth') 데코레이터들을 볼 수 있습니다.

"localhost:3000/auth"로 request 하면 이 클래스에서 처리한다는 의미이고, 데코레이터들을 기준으로 각 메서드들이 처리함을 의미합니다. 

"http://localhost:3000/auth/1"를 호출하였을 때 service 중 findOne메서드를 통해 메시지가 출력되었는데, controller에서는 @Get(':id')인 데코레이터를 가진 findOne이 호출되어 service를 호출한 것입니다.

':'으로 시작하는 문자열이 파라미터 값이구나 하는 걸 직관적으로 알 수 있으시겠죠?

 

> module

@Module({
  controllers: [AuthController],
  providers: [AuthService]
})
export class AuthModule {}

auth.module.ts를 살펴보면 굉장히 간단하지만 중요한 역할을 합니다.

auth폴더 내에 있는 resource들을 어떻게 이용하겠다!라고 선언해주는 부분이기 때문입니다.

controller는 AuthController를, providers는 AuthService를 이용한다는 의미입니다. 

마지막으로 AuthModule로 export 하여주는데, 이는 프로젝트 전체의 app.module.ts에서 확인해보면

@Module({
  imports: [SharedModule, AuthModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

"imports: [ "부분에 AuthModule이 import 되어 이용되는구나 확인할 수 있습니다.

 

 

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] app.controller 살펴보기  (0) 2022.03.02
[NestJS] 개발하기  (0) 2022.02.25
[NestJS] 시작하기  (0) 2022.02.25

app.controller.ts 소스 살펴보기

지난번엔 서버를 구동하여 "hello world"를 띄워 보았어요.

localhost의 root경로로 request가 response 되는 것을 확인한 것입니다.

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();
  }
}

app.controller.ts를 보면 Spring 프레임워크와 굉장히 익숙한 구조임을 알 수 있어요. 서버가 수행해야 할 일을 '@' Annotation, Decorator(어노테이션, 데코레이터)로 기술합니다.

 

@Controller 데코레이터를 클래스에 선언함으로써 해당 클래스는 컨트롤러의 역할을,

@Get() 데코레이터를 가진 getHello 함수는 root경로로 들어오는 request(요청)를 처리할 수 있습니다.

 

@Controller() 데코레이터를 보면 ( )가 있다. 여기에 인자를 입력하여 라우팅 경로는 정해줄 수 있어요. 예를들어 backend에서 주로 사용하는 'app'이라고 입력하면 우리가 지난번에 테스트했던 https://localhost:3000/app으로 접근해야 "hello world"를 만날 수 있는 것이죠!

  @Get('/helloworld')
  getHello(): string {
    return this.appService.getHello();
  }

@Get() 안에는 '/'가 생략되어 루트 경로이며, '/helloworld'로 변경한다면, 기존의 http://localhost:3000/ 요청에 대하여 404 에러를 만나게 될 것이고, http://localhost:3000/helloworld로 요청해야 "hello world"페이지를 응답받을 수 있을 것이다.

좌 : helloworld로 호출&nbsp; &nbsp; &nbsp; /&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 우 : root 호출&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;

 

소스로 보면 @Controller(에는 "prefix:", @Get(에는 "path"라고 붙여진 게 확실히 보여서 더 쉽게 이해할 수 있습니다.

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] 개발하기  (0) 2022.02.25
[NestJS] 시작하기  (0) 2022.02.25

1. Installation

Nest CLI를 통해 쉽게 프로젝트 생성할 수 있다.

npm i -g @nestjs/cli

npm을 통해 @nestjs/cli를 설치한다. -g 옵션을 통해 글로벌 환경에 설치하였다.

 

글로벌 환경의 설치 경로를 확인할 수 있다.

npm root -g

 

2. 프로젝트 생성

nest new [project name]

[procjet name]에 원하는 프로젝트 명을 입력하여 명령어를 실행한다.

 

⚡  We will scaffold your app in a few seconds..

CREATE bcheck-auth-nest/.eslintrc.js (631 bytes)
CREATE bcheck-auth-nest/.prettierrc (51 bytes)
CREATE bcheck-auth-nest/nest-cli.json (64 bytes)
CREATE bcheck-auth-nest/package.json (2005 bytes)
CREATE bcheck-auth-nest/README.md (3339 bytes)
CREATE bcheck-auth-nest/tsconfig.build.json (97 bytes)
CREATE bcheck-auth-nest/tsconfig.json (546 bytes)
CREATE bcheck-auth-nest/src/app.controller.spec.ts (617 bytes)
CREATE bcheck-auth-nest/src/app.controller.ts (274 bytes)
CREATE bcheck-auth-nest/src/app.module.ts (249 bytes)
CREATE bcheck-auth-nest/src/app.service.ts (142 bytes)
CREATE bcheck-auth-nest/src/main.ts (208 bytes)
CREATE bcheck-auth-nest/test/app.e2e-spec.ts (630 bytes)
CREATE bcheck-auth-nest/test/jest-e2e.json (183 bytes)

 

중간에 어떤 package manager를 사용할 것인지 물어본다. 필자는 yarn을 선택하였다.

? Which package manager would you ❤️  to use? yarn
✔ Installation in progress... ☕

🚀  Successfully created project bcheck-auth-nest
👉  Get started with the following commands:

$ cd [project name]
$ yarn run start


                          Thanks for installing Nest 🙏
                 Please consider donating to our open collective
                        to help us maintain this package.


               🍷  Donate: https://opencollective.com/nest

위와 같이 뜨면 프로젝트 생성이 완료된 것이다. 생성된 프로젝트를  개발 툴로 열어 구조를 살펴보자.

참고로 글쓴이는 IntelliJ를 이용한다.

[Project Name] - [src] 아래에 app.으로 시작하는 파일들과 main.ts 파일이 생성되었음을 확인할 수 있다.

각각의 역할은 아래와 같다.

app.controller.spec.ts 컨트롤러 단위 테스트용
app.controller.ts 기본 컨트롤러
app.module.ts application의 root module
app.service.ts 단일 메서드를 사용하는 기본 서비스
main.ts NestFactory를 사용하여 Nest application 인스턴스를 작성하는 엔트리 파일

 

3. 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();

Nest application은 인스턴스를 생성하기 위해 NestFactory를 사용한다. NestFactory는 application 응용프로그램 인스턴스를 만들 수 있는 정적 메서드를 제공하며, careate() 메서드는 INestApplication (인터페이스 응용프로그램 객체)을 반환한다.

 

4. Running the application

아래의 명령어로 인바운드 HTTP 요청을 수신하는 애플리케이션을 시작할 수 있다.

npm run start

 

main.ts에 정의한 port에서 수신하는 HTTP 서버로 앱을 시작하므로

http://localhost:3000/ 에 접속하면 귀여운 "Hello World!"를 볼 수 있다.

 

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] app.controller 살펴보기  (0) 2022.03.02
[NestJS] 시작하기  (0) 2022.02.25

Spring 개발 유경험자로 Node를 처음 접하며 Study하는 내용을 기록해보고자 한다. 

 

1. NestJS는?

 

NestJS는 Node.js 기반의 웹 API 프레임워크이다. 들어만 본 Express를 사용하고, Node.js의 자체 특성인 사용하기 쉽고, 확장성이 뛰어나다. 이로 인해 품질이 일정치 않고, 적합한 라이브러리를 찾기 위해 사용자의 수고가 필요하다는 단점이 있는데 이를 보완하는 것이 NestJS이다.

 

Angular의 영향을 많이 받은 NestJS는 DI(Dependency Injection, 의존성 주입)이라는 객체지향 개념을 도입한 부분에서 Spring과 공통점이 있다. 소스를 보아도 스프링에서 Anotation이라고 불리는 '@'가 보인다.

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

NestJS에서는 Decorator라고 부르며 이에대한 설명은 다음에 하도록 하고 

그동안의 Angular, React, Vue와 같은 JS들의 어떤 문제점이 NestJS에서 해결되었을까?

Node 하면 떠오르는 Express와는 무엇이 달라졌을까? 에 대해 살펴보자.

 

2. Nest VS Express

controller, service, module 패턴으로 통일성, 생산성 향상 높은 자유도 (개발자들의 선택의 폭이 넓음)
선택지(라이브러리 등)를 찾는 시간과 노력 필요
-> 통일성, 일관성이 떨어짐
typescript가 기본 설정. 바닐라 자바스크립트도 가능 추가 설정을 통해 typescript 사용 가능

Nest와 Express 공식 홈페이지 및 커뮤니티의 글을 통해 본 각각의 특징들이다.

내가 느낀바로 요약하면 "Express의 높은 자유도로 인한 선택 장애를 Nest가 해결해준다"이다.

 

아래는 각각의 공식 홈페이지이며 다음 글에서는 본격적으로 NestJS 프로젝트를 만들어보도록 하자.

 

NestJS https://nestjs.com/

 

NestJS - A progressive Node.js framework

NestJS is a framework for building efficient, scalable Node.js web applications. It uses modern JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Progr

nestjs.com

 

Express https://expressjs.com/

 

Express - Node.js web application framework

Fast, unopinionated, minimalist web framework for Node.js $ npm install express --save

expressjs.com

 

728x90
반응형

'NestJS' 카테고리의 다른 글

[NestJS] swagger에서 테스트하기  (0) 2022.03.23
[NestJS] Authentication 구현  (0) 2022.03.18
[NestJS] CRUD 구현해보기  (0) 2022.03.07
[NestJS] app.controller 살펴보기  (0) 2022.03.02
[NestJS] 개발하기  (0) 2022.02.25

+ Recent posts