26 Jan 2021 |
Backend
Nestjs 튜토리얼 따라하기 6편
Exception filters

- Nest의 모든 예외를 처리하는 Exception filters가 존재
Nest는 기본적으로 HttpException
이 내장되어 있으며 이는 @nestjs/common
패키지에서 불러올 수 있다.
@Get()
async findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
HttpException
은 2개의 인수로 구성된다.
response
: response를 정의한다. 이는 object일 수 있으며 string일 수도 있다.
status
: HTTP 상태 코드를 정의한다.
response
의 JSON object는 2가지 속성이 필요하다.
statusCode
: 기본값은 status 값에 작성된 값
message
: HTTP 오류에 대한 설명
@Get()
async findAll() {
throw new HttpException({
status: HttpStatus.FORBIDDEN,
error: 'This is a custom message',
}, HttpStatus.FORBIDDEN);
}
{
"status": 403,
"error": "This is a custom message"
}
Exception filters
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
모든 Exception filters는 implements ExceptionFilter
를 포함하여야 한다.
위에서 구현한 HttpExceptionFilter
를 적용하는 방법은 아래와 같다.
@Post()
@UseFilters(new HttpExceptionFilter())
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
여기서 @UseFilters()
는 @nestjs/common
패키지에서 제공된다.
또한 필터를 전역으로 적용하기 위하여 아래와 같이 코드를 작성한다.
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
bootstrap();
혹은 모듈 단위로 필터를 적용할 수 있다.
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
},
],
})
export class AppModule {}
26 Jan 2021 |
Backend
Nestjs 튜토리얼 따라하기 5편
Middleware

- Middleware는 요청 및 응답에 엑세스 가능
Nest의 Middleware는 Express의 Middleware와 동일하다.
Express의 공식 문서에서 설명하는 미들웨어의 기능은 아래와 같다.
execute any code.
make changes to the request and the response objects.
end the request-response cycle.
call the next middleware function in the stack.
if the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function.
Otherwise, the request will be left hanging.
Nest의 Middleware는 함수나 @Injectable()
데코레이터가 있는 클래스에서 구현 된다.
// logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log('Request...');
next();
}
}
또한 Nest의 Middleware는 모듈 내에서 사용할 수 있는 종속성을 생성자를 이용하여 삽입할 수 있다.
Nest의 Middleware 적용을 위해서 Module클래스 내에서 configure()
를 사용하여야 한다. 또한 Middleware를 포함하는 모듈은 NestModule
인터페이스를 implements NestModule
형식으로 사용하여야 한다.
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('cats');
}
}
또한 Middleware를 특정 Method로 제한할 수 있다.
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET });
}
}
와일드카드도 적용이 가능하다.
import { Module, NestModule, RequestMethod, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });
}
}
Middleware 또한 전역으로 선언할 수 있다
const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
26 Jan 2021 |
Backend
Nestjs 튜토리얼 따라하기 4편
Modules

- Module은 어플리케이션의 구조를 구성하는데 사용
@Module()
데코레이터를 사용
# scr폴더 내에 cats폴더 생성
nest g module cats
위 명령어를 이용하여 프로젝트를 생성하면 다음과 같은 구조를 가진다.
├── src
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── main.ts
│ └── cats
│ └── cats.module.ts
cats.module.ts에 다음과 같은 코드를 입력한다.
// cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
또한 여기서 생성된 CatsModule을 루트 모듈로 연결시켜 준다.
// app.module.ts
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
이제 루트 모듈은 CatsModule에 접근할 수 있게된다.
Global Module
모든 곳에서 동일한 모듈을 가져오기 위해서 모든 module.ts에 동일한 선언을 한다면 그것은 비효율적일 것이다. 이 같은 경우를 위해서 @Global()
을 이용하여 Module을 전역으로 설정할 수 있다.
import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Global()
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
전역으로 선언된 모듈은 루트 혹은 코어 모듈에서 한번만 등록해야 한다.
26 Jan 2021 |
Backend
Nestjs 튜토리얼 따라하기 3편
Providers

- Provider는 종속성을 주입하는 기능을 수행함
@Injectable()
데코레이터를 사용
# scr폴더 내에 cats폴더 생성
nest g service cats
위 명령어를 이용하여 프로젝트를 생성하면 다음과 같은 구조를 가진다.
├── src
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── main.ts
│ └── cats
│ └── cats.service.ts
cats.service.ts에 다음과 같은 코드를 입력한다.
// cats.service.ts
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
이를 사용하기 위해서 CatsController에 연결해준다.
// cats.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
생성자를 통하여 catsService를 선언하고 catsService에 선언된 함수를 사용하였다.
CatsService, CatsController를 정의하였으므로 이를 수행할 수 있도록 module에 등록하여야 한다.
// app.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class AppModule {}
17 Jan 2021 |
PS
AtCoder Beginner Contest 188 B번 ABC Tournament
문제
https://atcoder.jp/contests/abc188/tasks/abc188_c

풀이
길이가 2^N인 수열 N이 있고 수열 N은 i번째 플레이어의 레이팅을 나타낸다고 했을 때
모든 플레이어가 토너먼트식으로 진행을 할 때 2등을 하는 플레이어는 누군지 선택하는 문제
토너먼트로 진행이 되므로 결승전은 수열 N을 반으로 나누어 만든 두 그룹 중, 앞 그룹 중 1등 vs 뒷 그룹 중 1등의 결승 대진이 확정된다.
결승전에서 진 플레이어가 2등이므로 해당 플레이어의 인덱스를 출력하면 정답
코드
#pragma warning(disable : 4996)
#include <bits/stdc++.h>
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef vector<ll> vll;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pld;
typedef tuple<ll, ll, ll> tl3;
#define FOR(a, b, c) for (int(a) = (b); (a) < (c); ++(a))
#define FORN(a, b, c) for (int(a) = (b); (a) <= (c); ++(a))
#define rep(i, n) FOR(i, 0, n)
#define repn(i, n) FORN(i, 1, n)
#define tc(t) while (t--)
// https://atcoder.jp/contests/abc188/tasks/abc188_c
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n;
cin >> n;
vll a(pow(2,n));
for(int i = 0;i<pow(2,n);i++){
cin >> a[i];
}
ll max1 = 0, max2 = 0;
ll idx1 = 0, idx2 = 0;
for(int i = 0;i<a.size()/2;i++){
if(max1 < a[i]){
max1 = a[i];
idx1 = i+1;
}
}
for(int i = a.size()/2;i<a.size();i++){
if(max2 < a[i]){
max2 = a[i];
idx2 = i+1;
}
}
if(max1 > max2) cout << idx2;
else cout << idx1;
return 0;
}