Fastify で decorate plugin を nested register で書く場合の注意点


Fastify で Decorators を使う

fastify の decorators は非常に便利。

ただ、nest された register で decorators を登録しようとする場合、全てを 'fastify-plugin' で囲む必要があるので注意。

きちんとドキュメントを読めばわかるが、軽く内容をメモしておく。
https://www.fastify.io/docs/latest/Plugins-Guide/#decorators

decorators は子の register でしか使えない

まず大前提の知識として、FastifyInstance に生やした decorator はその配下の FastifyInstance でしか使えない。

fastify.register((instance, opts, done) => {
  instance.decorate('util', (a, b) => a + b)
  console.log(instance.util('that is ', 'awesome'))

  fastify.register((instance, opts, done) => {
    console.log(instance.util('that is ', 'awesome')) // これは上手く動く
    done()
  })

  done()
})

fastify.register((instance, opts, done) => {
  console.log(instance.util('that is ', 'awesome')) // これはエラーになる

  done()
})

'fastify-plugin' で囲めば、同じ階層でも使えるようになる。

import fp from 'fastify-plugin';

// register する中身を 'fastify-plugin' でラップしている
fastify.register(fp((instance, opts, done) => {
  instance.decorate('util', (a, b) => a + b)
  console.log(instance.util('that is ', 'awesome'))

  fastify.register((instance, opts, done) => {
    console.log(instance.util('that is ', 'awesome')) // これは上手く動く
    done()
  })

  done()
}))

fastify.register((instance, opts, done) => {
  console.log(instance.util('that is ', 'awesome')) // これも上手く動く

  done()
})

.register をネストさせる場合は、その全ての階層で 'fastify-plugin' で囲む必要がある

当たり前といえば当たり前だが...

簡略化のために1ファイルに全て書いていますが、本来は registerPlugins 以降は別ファイルに定義することを想定しています。そのため、定義の順番とかは適当なので悪しからず

import fastify, { FastifyPluginCallback } from 'fastify';
import fp from 'fastify-plugin';

const app = fastify();
app.register(fp(registerPlugins));

app.MAIN_PROPERTY // アクセスできる。(どこか1つでも fp が外れると、読めなくなる)

const registerPlugins: FastifyPluginCallback = (app, _ops, done) => {
  app.register(fp(registerMainPlugins));
  app.register(fp(registerSubPlugins));
  done();
};

const registerMainPlugins: FastifyPluginCallback = (app, _ops, done) => {
  app.register(fp(xxxPluginCallback));
  done();
};

const xxxPluginCallback: FastifyPluginCallback = (app, _opts, done) => {
  app.decorate(MAIN_PROPERTY, MAIN_VALUE);
  done();
};

const registerSubPlugins: FastifyPluginCallback = (app, _ops, done) => {
  app.register(fp(yyyPluginCallback));
  done();
};

const yyyPluginCallback: FastifyPluginCallback = (app, _opts, done) => {
  app.decorate(SUB_PROPERTY, SUB_VALUE);
  done();
};