Fastify

Fastify는 Node.js를 위한 빠르고 낮은 오버헤드의 웹 프레임워크. 2016년에 처음 출시되었으며, 성능과 개발자 경험을 모두 중요하게 고려하여 설계되었다.
Express.js와 유사한 API를 제공하면서도, JSON 스키마를 기반으로 한 검증과 높은 성능이 특징이다.

주요 특징

  1. 높은 성능: 최적화된 HTTP 레이어를 통해 높은 처리량과 낮은 지연 시간 제공
  2. JSON 스키마 기반 검증: 내장된 데이터 검증 및 직렬화 기능
  3. 플러그인 아키텍처: 강력한 확장성을 위한 모듈식 구조
  4. 비동기 지원: async/await를 기본적으로 지원
  5. TypeScript 지원: 타입 안전성과 자동 완성 기능 제공

장점

  1. 뛰어난 성능: 초당 많은 요청을 처리할 수 있는 높은 처리량
  2. 개발자 친화적: 직관적인 API와 풍부한 문서 제공
  3. 유연성: 다양한 플러그인과 미들웨어 지원
  4. 보안: 내장된 보안 기능과 데이터 검증

단점 및 한계

  1. 학습 곡선: 초보자에게는 다소 복잡할 수 있음
  2. 생태계 규모: Express.js에 비해 상대적으로 작은 커뮤니티와 플러그인 생태계

사용 방법

기본적인 설치와 서버 설정부터 살펴보겠습니다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 설치
npm install fastify

// 기본 서버 설정
const fastify = require('fastify')({ logger: true });

// 라우트 정의
fastify.get('/', async (request, reply) => {
  return { hello: 'world' };
});

// 서버 시작
const start = async () => {
  try {
    await fastify.listen({ port: 3000 });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

주요 명령어

  • fastify.get()fastify.post() 등: 라우트 정의
  • fastify.register(): 플러그인 등록
  • fastify.listen(): 서버 시작
  • fastify.log: 로깅

Fastify의 주요 기능

이제 더 복잡한 예시를 통한 Fastify의 주요 기능들

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
const fastify = require('fastify')({ 
  logger: {
    level: 'info',
    prettyPrint: true
  }
});

// JSON 스키마 정의
const userSchema = {
  type: 'object',
  properties: {
    id: { type: 'integer' },
    name: { type: 'string' },
    email: { type: 'string', format: 'email' }
  },
  required: ['name', 'email']
};

// 사용자 데이터 저장소
const users = new Map();

// 플러그인 정의
const usersPlugin = async (fastify, options) => {
  // CREATE
  fastify.post('/users', {
    schema: {
      body: userSchema,
      response: {
        201: userSchema
      }
    }
  }, async (request, reply) => {
    const { name, email } = request.body;
    const id = users.size + 1;
    const user = { id, name, email };
    users.set(id, user);
    reply.code(201);
    return user;
  });

  // READ
  fastify.get('/users/:id', {
    schema: {
      params: {
        type: 'object',
        properties: {
          id: { type: 'string' }
        }
      },
      response: {
        200: userSchema,
        404: {
          type: 'object',
          properties: {
            message: { type: 'string' }
          }
        }
      }
    }
  }, async (request, reply) => {
    const id = parseInt(request.params.id);
    const user = users.get(id);
    
    if (!user) {
      reply.code(404);
      return { message: 'User not found' };
    }
    
    return user;
  });

  // UPDATE
  fastify.put('/users/:id', {
    schema: {
      params: {
        type: 'object',
        properties: {
          id: { type: 'string' }
        }
      },
      body: userSchema,
      response: {
        200: userSchema
      }
    }
  }, async (request, reply) => {
    const id = parseInt(request.params.id);
    const { name, email } = request.body;
    
    if (!users.has(id)) {
      reply.code(404);
      return { message: 'User not found' };
    }
    
    const user = { id, name, email };
    users.set(id, user);
    return user;
  });

  // DELETE
  fastify.delete('/users/:id', {
    schema: {
      params: {
        type: 'object',
        properties: {
          id: { type: 'string' }
        }
      }
    }
  }, async (request, reply) => {
    const id = parseInt(request.params.id);
    
    if (!users.has(id)) {
      reply.code(404);
      return { message: 'User not found' };
    }
    
    users.delete(id);
    reply.code(204);
  });
};

// 훅 사용 예시
fastify.addHook('preHandler', async (request, reply) => {
  // 요청 처리 전에 실행되는 코드
  request.log.info(`Incoming ${request.method} request to ${request.url}`);
});

// 플러그인 등록
fastify.register(usersPlugin);

// 커스텀 에러 핸들러
fastify.setErrorHandler((error, request, reply) => {
  request.log.error(error);
  reply.status(500).send({ error: 'Something went wrong' });
});

// 데코레이터 추가
fastify.decorateRequest('timestamp', null);
fastify.addHook('onRequest', async (request) => {
  request.timestamp = new Date();
});

// 서버 시작
const start = async () => {
  try {
    await fastify.listen({ port: 3000 });
    fastify.log.info(`Server listening on ${fastify.server.address().port}`);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

주요 명령어와 기능

  1. 라우팅 메서드:

    1
    2
    3
    4
    5
    
    fastify.get()
    fastify.post()
    fastify.put()
    fastify.delete()
    fastify.patch()
    
  2. 미들웨어와 훅:

    1
    2
    3
    
    fastify.addHook('onRequest', async (request, reply) => {})
    fastify.addHook('preHandler', async (request, reply) => {})
    fastify.addHook('onResponse', async (request, reply) => {})
    
  3. 플러그인 관련:

    1
    2
    3
    4
    
    fastify.register(plugin, options)
    fastify.decorate(name, value)
    fastify.decorateRequest(name, value)
    fastify.decorateReply(name, value)
    
  4. 유효성 검사:

    1
    2
    3
    4
    5
    6
    7
    8
    
    fastify.route({
      schema: {
        body: schema,
        querystring: schema,
        params: schema,
        response: schema
      }
    })
    

참고 및 출처

Fast and low overhead web framework, for Node.js | Fastify