NestJS 개발 시작하기(로그인 인증 개발)
3. API개발과 Swagger
4. Auth API
앞에서 이번 Auth API의 개발 요구사항을
- Auth는 signup, signin, signout의 3가지 API를 제공,
- 개인 정보는 email을 userid로 동일하게 사용하고, 사용자 명, password
를 제공하는 것으로 잡았으니, 이를 기준으로 하는 간단한 API를 만들어 보자.
a. Swagger
API 개발에는 OpenAPI, Swagger패키지를 사용하면 개발하면서 만들어진 부분을 쉽게 테스트해 볼 수 있다. Swagger를 사용하기 위해서는 먼저 @nestjs/swagger를 설치하고
pnpm install @nestjs/swagger
main.ts를 아래와 같이 수정한다.
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// added for swagger
const config = new DocumentBuilder()
.setTitle('Sensor server')
.setDescription('Sensor data receiver API description')
.setVersion('1.0')
.addTag('sensors')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
// end of swagger
await app.listen(3000);
}
b. Controller
Sign up, in, out 세 개의 API에 대해 다음과 같이 정의했다. SignIn도 같은 방법으로 정보전달 Schema를 정의할 수 있겠지만, API를 만드는 다양한 방법에 대해 기록을 남기기 위해 다른 방식을 사용했다.
URL | HTTP 방식 | 설명 | 전달정보 |
/sign/up | POST | 신규생성 | Body로 정보 전달. Body는 SignUpDto로 정의 |
/sign/in | GET | 로그인 | path parameter로 id, query로 passwd를 전달 |
/sign/out | GET | 로그아웃 | path parameter로 id 전달 |
먼저 SignUpDto를 하나 만들자.
import { ApiProperty } from "@nestjs/swagger";
export class SigninDto {
@ApiProperty()
id: string;
@ApiProperty()
passwd: string;
}
앞에서 생성한 sign.controller에 API의 내용을 아래와 같이 만들 수 있다. Controller는 주로 routing을 위한 목적으로 사용하는 것이 좋은데, HTTP의 어떤 방식으로 받을 것인지와 path를 먼저 annotation으로 @Post('up')과 같이 선언하고, debug를 위한 목적으로 log를 남기고, 뒤에서 만들 Service의 함수를 호출하는 정도록 작성하면 된다.
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common';
import { SignUpDto } from '../dto/SignUpDto';
import { SignService } from './sign.service';
@Controller('sign')
export class SignController {
constructor(private readonly signService: SignService) {}
@Post('up')
signUp(@Body() signUpDto: SignUpDto) {
console.debug('Sign up\n' + 'SignUpDto = ' + JSON.stringify(signUpDto));
const result = this.signService.createAccount(signUpDto);
return 'Sign up' + (result ? ' success' : ' failed');
}
@Get('in/:id')
signIn(@Param('id') id: string, @Query('password') password: string) {
console.debug('Sign in\n' + 'id = '+ id + ', password = ' + password);
const result = this.signService.login(id, password);
return 'Sign in ' + (result ? 'success' : 'failed');
}
@Get('out/:id')
signOut(@Param('id') id: string) {
console.debug('Sign in\n' + 'id = '+ id);
const result = this.signService.logout(id);
return 'Sign out' + (result ? ' success' : ' failed');
}
}
c. Service
DB와 ORM(Object-Relational Mapping)와 암호화에 대해서는 다음 글에서 정리하기로 하고, 이번에는 메모리에 간단히 저장하는 방식으로 Service를 구현했다. 메모리에 저장할 자료 구조는 요구사항에 있는 내용처럼 email, 패스워드, 사용자명을 저장할 수 있게 아래와 같은 내용으로 Account로 정의했다.
import { ApiProperty } from "@nestjs/swagger";
export class SignUpDto {
@ApiProperty()
email: string;
@ApiProperty()
password: string;
@ApiProperty()
name: string;
}
파일은 nest CLI의 generate 명령을 사용해서 자동으로 만들 수도 있다.
nest g interface account auth/interface --flat
Service는 아래와 같이 계정정보를 저장하는 Account배열과 세션은 없지만 로그인 상태를 저장하는 isLogedin배열을 사용해서 정보를 저장했다. createAccount, login, logout 세 개의 함수로 정의하고 모두 처리 결과를 boolean으로 돌려주는 형식으로 만들었고, 모든 함수에서 공통으로 사용되는 Account검색을 위한 find를 추가로 만들었다.
import { Injectable } from '@nestjs/common';
import { Account } from '../interface/account.interface';
@Injectable()
export class SignService {
accounts: Account[] = [];
isLogedin: boolean[] = [];
find(email: string): Account {
return this.accounts.find(account => account.email === email);
}
createAccount(account: Account) : boolean {
if (this.find(account.email) == undefined) {
this.accounts.push(account);
this.isLogedin.push(false);
return true;
}
return false;
}
login(email: string, password: string): boolean {
const account = this.find(email);
if (account != undefined && account.password === password) {
this.isLogedin[this.accounts.indexOf(account)] = true;
return true;
}
return false;
}
logout(email: string): boolean {
const account = this.find(email);
if (account != undefined) {
this.isLogedin[this.accounts.indexOf(account)] = false;
return true;
}
return false;
}
}
이제 기본적인 로직을 만들었으면, http://localhost:3000/api으로 접속해서 swagger로 API를 테스트해 볼 수 있다. swgger를 사용하더라도 테스트 케이스는 작성해서 CI (Continuous Integration)에서 검증하는 절차를 거치도록 하는 것이 좋다.
하나 재미있는 사실은, 만약 이전 글에서 소개한 적이 있는 Github Copilot을 사용하고 있다면, 위의 코드를 작성할 때 적어도 절반 이상은 AI가 자동으로 만들어 준다는 점이다. 개발 시간이 아마 절반이하로 줄었지 않았을까?
'프로그램 개발' 카테고리의 다른 글
파이썬 딥러닝 개발환경; 2. Keras 설치, MNIST 학습 테스트 (13) | 2024.10.05 |
---|---|
NestJS 개발 시작하기(로그인 인증 개발); 4. TypeORM으로 DB연결 (1) | 2024.09.28 |
NestJS 개발 시작하기(로그인 인증 개발); 2. NestJS CLI로 개발시작 (0) | 2024.09.21 |
NestJS 개발 시작하기(로그인 인증 개발); 1. NestJS와 Spring의 비교 (4) | 2024.09.17 |
엘라스틱서치(ELK)로 만드는 모니터링 시스템; 3. Filebeat- App Log수집 (2) | 2024.09.14 |