Node.js 생태계에서 Fastify는 뛰어난 성능과 플러그인 기반 아키텍처로 API 구축에 선호되는 프레임워크 중 하나입니다. Fastify의 데코레이터 기능은 개발자가 요청(Request) 및 응답(Response) 객체와 같은 핵심 객체를 선언적인 방식으로 확장하고 강화할 수 있게 해줍니다. 이 글에서는 Fastify 데코레이터의 기본 개념을 살펴보고, 실제 예제를 통해 API 성능과 기능을 어떻게 향상시킬 수 있는지 알아봅니다.
Fastify 데코레이터란?
Fastify 데코레이터는 Fastify의 핵심 객체에 사용자 정의 속성과 메서드를 추가할 수 있는 강력한 도구입니다. 이러한 데코레이터는 서버 인스턴스, 요청 객체, 응답 객체에 적용될 수 있으며, 내부 구현을 수정하지 않고도 Fastify의 기능을 유연하게 확장할 수 있는 방법을 제공합니다.
데코레이터의 역할
- 성능 최적화: 객체의 구조를 미리 정의함으로써 JavaScript 엔진이 객체 처리를 최적화하여 성능을 향상시킵니다.
- 기능 확장: 핵심 코드 변경 없이 Fastify 객체에 새로운 메서드와 속성을 추가할 수 있습니다.
- 코드 재사용: 동일한 로직을 여러 곳에서 재사용할 수 있도록 지원하여 코드 유지보수성을 높입니다.
Fastify 데코레이터로 요청 로깅 구현하기
다음은 Fastify 데코레이터를 사용하여 요청 로깅 기능을 구현하는 예제입니다:
const Fastify = require('fastify');
const fastify = Fastify();
// 로깅을 위한 미들웨어 데코레이터
fastify.addHook('preHandler', (request, reply, done) => {
console.log('요청 수신:', request.url);
done();
});
// 요청 객체에 사용자 정의 속성 추가
fastify.decorateRequest('logger', {
info: () => console.log('요청 객체에서 정보 로그')
});
// 데코레이터로 추가된 속성 사용
fastify.get('/', (request, reply) => {
request.logger.info();
reply.send('Hello World!');
});
fastify.listen(3000, (err, address) => {
if (err) throw err;
console.log(`서버 실행 중: ${address}`);
});
이 예제에서는 먼저 addHook 메서드를 사용하여 각 요청 전에 URL을 기록하는 preHandler 훅을 추가합니다. 그런 다음 decorateRequest 데코레이터를 사용하여 요청 객체에 info 메서드를 가진 logger라는 사용자 정의 속성을 추가합니다. 마지막으로 라우트 핸들러에서 이 사용자 정의 logger 속성을 호출합니다.
Fastify 데코레이터의 다양한 활용을 보여주기 위해 다섯 가지 간단한 예제를 준비했습니다:
예제 1: add(x, y) 메서드 추가
const Fastify = require('fastify');
const fastify = Fastify();
// Fastify 인스턴스에 사용자 정의 메서드 추가
fastify.decorate('add', function (x, y) {
return x + y;
});
// 추가된 메서드 사용
fastify.get('/add/:x/:y', (request, reply) => {
const sum = request.server.add(Number(request.params.x), Number(request.params.y));
reply.send({ result: sum });
});
fastify.listen(3000);
이 예제에서는 decorate 데코레이터를 사용하여 Fastify 서버 인스턴스에 두 숫자의 합을 계산하는 add 메서드를 추가합니다. 라우트 핸들러에서 이 메서드를 호출하여 GET 요청에 응답합니다.
예제 2: 토큰 검증
const Fastify = require('fastify');
const fastify = Fastify();
// 토큰 검증 데코레이터
fastify.decorate('authenticate', async (request, reply) => {
const token = request.headers['authorization'];
if (!token || token !== 'secret-token') {
reply.status(401).send({ error: '인증 실패' });
return false;
}
return true;
});
// 데코레이터로 토큰 검증
fastify.get('/protected', async (request, reply) => {
if (!await request.server.authenticate(request, reply)) {
return;
}
reply.send({ content: '보호된 콘텐츠입니다' });
});
fastify.listen(3000);
이 예제에서는 요청 헤더의 Authorization 필드가 올바른 토큰인지 확인하는 authenticate 데코레이터를 만듭니다. 검증에 실패하면 401 상태 코드를 반환합니다.
예제 3: 요청 로그 기록
const Fastify = require('fastify');
const fastify = Fastify();
// 요청 객체에 로깅 기능 추가
fastify.decorateRequest('log', {
requestLogger: (msg) => console.log(`요청 로그: ${msg}`)
});
// 추가된 로깅 기능 사용
fastify.get('/log', (request, reply) => {
request.log.requestLogger('/log 경로에 GET 요청 수신');
reply.send({ message: '요청 기록 완료' });
});
fastify.listen(3000);
이 예제에서는 decorateRequest 데코레이터로 요청 객체에 requestLogger 메서드를 포함한 log 속성을 추가합니다.
예제 4: 응답 시간 헤더 설정
const Fastify = require('fastify');
const fastify = Fastify();
// 응답 객체에 응답 시간 헤더 설정 기능 추가
fastify.decorateReply('setResponseTime', function (time) {
this.header('X-Response-Time', time);
});
// 추가된 기능 사용
fastify.get('/time', (request, reply) => {
const startTime = Date.now();
// 비동기 작업 시뮬레이션
setTimeout(() => {
const responseTime = Date.now() - startTime;
reply.setResponseTime(responseTime).send({ message: '응답 시간 설정됨' });
}, 1000);
});
fastify.listen(3000);
이 예제에서는 decorateReply 데코레이터를 사용하여 응답 객체에 X-Response-Time 헤더를 설정하는 setResponseTime 메서드를 추가합니다.
예제 5: 사용자 정의 에러 처리
const Fastify = require('fastify');
const fastify = Fastify();
// Fastify 인스턴스에 사용자 정의 에러 처리 추가
fastify.decorate('customError', function (msg) {
throw new Error(msg);
});
// 사용자 정의 에러 처리 사용
fastify.get('/error', (request, reply) => {
request.server.customError('문제가 발생했습니다');
});
fastify.setErrorHandler((error, request, reply) => {
reply.status(500).send({ error: error.message });
});
fastify.listen(3000);
이 예제에서는 decorate 데코레이터로 Fastify 인스턴스에 사용자 정의 에러를 발생시키는 customError 메서드를 추가하고, 에러 핸들러를 설정하여 500 상태 코드를 반환하도록 합니다.
마치며
Fastify 데코레이터는 API 성능을 높이고 기능을 선언적으로 확장할 수 있는 강력한 도구입니다. 데코레이터 사용 시 다음 사항을 염두에 두세요:
- 성능 영향: 데코레이터는 객체 구조를 미리 정의하여 성능을 최적화하며, 런타임에 동적으로 속성을 추가하는 것을 피해 성능 저하를 방지합니다.
- 코드 구성: 데코레이터를 적절히 사용하면 코드를 모듈화하고 유지보수하기 쉽게 구성할 수 있습니다.
- 비동기 데코레이터: 비동기 방식으로 데코레이터를 정의해야 한다면
register메서드와fastify-plugin을 활용하세요.
이 글이 Fastify 데코레이터를 이해하고 사용하는 데 도움이 되길 바랍니다. 더 깊이 있는 내용이 필요하다면 Fastify 공식 문서를 참조하세요.