ウェブエンジニア問題集
第7章

Fastifyのpluginsとencapsulation — 機能単位でAPIを分割する

4
この章の目次開く

Fastifyでは、機能を分割するときにpluginを使います。pluginは「ルート、hooks、decorator、設定をまとめた部品」です。そしてFastifyのpluginには、encapsulation という重要な性質があります。

Fastifyのpluginは、単なるファイル分割ではありません。登録した範囲にだけ設定やhooksを効かせるための境界です。

register() の構文

構文: fastify.register(plugin, options)

引数説明
pluginfunctionFastifyインスタンスを受け取ってルートなどを登録する関数
optionsobjectpluginへ渡す設定。prefix なども指定できる

戻り値: Fastifyインスタンス。登録処理として使います。

fastify.register(todoRoutes, { prefix: '/todos' });
js

ルートをpluginに分ける

src/routes/todos.js を作ります。

const todos = [
  { id: 1, title: 'Fastifyを学ぶ', completed: false },
];
 
export async function todoRoutes(fastify) {
  fastify.get('/', async () => {
    return todos;
  });
 
  fastify.get('/:id', async (request, reply) => {
    const todo = todos.find((item) => item.id === Number(request.params.id));
 
    if (!todo) {
      return reply.code(404).send({ error: 'TODO_NOT_FOUND' });
    }
 
    return todo;
  });
}
js

src/app.js で登録します。

import Fastify from 'fastify';
import { todoRoutes } from './routes/todos.js';
 
export function buildApp() {
  const fastify = Fastify({ logger: true });
 
  fastify.register(todoRoutes, { prefix: '/todos' });
 
  return fastify;
}
js

この場合、plugin内の //todos/:id/todos/:id として公開されます。

encapsulationとは

Fastifyのpluginは、親子関係を持つスコープを作ります。pluginの中で登録したhookやdecoratorは、基本的にそのpluginと子pluginの中で有効になります。

たとえば、管理画面用のpluginだけに認証hookを付けたい場合、/admin 配下に閉じ込められます。

async function adminRoutes(fastify) {
  fastify.addHook('preHandler', async (request, reply) => {
    if (request.headers.authorization !== 'Bearer secret') {
      return reply.code(401).send({ error: 'UNAUTHORIZED' });
    }
  });
 
  fastify.get('/stats', async () => {
    return { users: 10 };
  });
}
 
fastify.register(adminRoutes, { prefix: '/admin' });
js

このhookは /admin/stats には効きますが、別のpluginとして登録した /todos には効きません。

学習者学習者

Expressの app.use('/admin', auth) と似ていますか?

先生先生

近いですが、Fastifyではhooksやdecoratorもスコープに閉じ込められます。大きいAPIほど、この境界が効いてきます。

prefixでURLをまとめる

register()prefix を使うと、plugin内のルートに共通のURLを付けられます。

fastify.register(todoRoutes, { prefix: '/api/todos' });
fastify.register(adminRoutes, { prefix: '/api/admin' });
js
plugin内のpathprefix実際のURL
//api/todos/api/todos
/:id/api/todos/api/todos/:id
/stats/api/admin/api/admin/stats

参考リンク

次章では、リクエストのライフサイクルに処理を差し込むhooksを学びます。

Node.jsクイズに挑戦するモジュール分割やHTTPサーバーの知識をクイズで確認しよう