Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

fastify-plugin и декораторы

Декоратор — свойство или метод, который вы добавляете к экземпляру Fastify, к запросу или к ответу. Так общие объекты — хранилище статей, подключение к базе, функция проверки — становятся доступны во всех маршрутах без глобальных переменных.

decorate

Пусть статьи хранятся в отдельном модуле. Создайте плагин src/plugins/store.js:

// src/plugins/store.js
export default async function store(app) {
  const posts = [
    { id: 1, title: 'Первая статья', body: 'Текст' },
  ];
 
  app.decorate('posts', posts);
}

app.decorate('posts', posts) добавляет свойство app.posts. Но из-за инкапсуляции оно видно только внутри этого плагина — маршруты в routes/posts.js его не увидят.

fastify-plugin

Пакет fastify-plugin снимает инкапсуляцию: всё, что добавил обёрнутый плагин, попадает в родительский контекст.

npm install fastify-plugin

Оберните плагин:

// src/plugins/store.js
import fp from 'fastify-plugin';
 
async function store(app) {
  const posts = [
    { id: 1, title: 'Первая статья', body: 'Текст' },
  ];
 
  app.decorate('posts', posts);
}
 
export default fp(store);

Подключите его в src/app.js раньше маршрутов, чтобы к их загрузке свойство уже существовало:

// src/app.js
import store from './plugins/store.js';
import postRoutes from './routes/posts.js';
 
app.register(store);
app.register(postRoutes);

Использование в маршрутах

Внутри плагина маршрутов свойство доступно через app, а в обработчике — ещё и через this:

// src/routes/posts.js
export default async function postRoutes(app) {
  app.get('/posts', async () => {
    return app.posts;
  });
}

http://localhost:3000/posts вернёт статьи из хранилища. Когда позже появится база данных, поменяется только плагин, а маршруты останутся прежними.

decorateRequest

Свойства запроса объявляют заранее через decorateRequest, а значение заполняют для каждого запроса — обычно в хуке:

// src/plugins/timing.js
import fp from 'fastify-plugin';
 
async function timing(app) {
  app.decorateRequest('startTime', 0);
}
 
export default fp(timing);

Подключите плагин в src/app.js через app.register(timing). Теперь у каждого request есть свойство startTime со значением 0. В уроке о хуках туда будет записываться время начала запроса.

Виды декораторов

МетодКуда добавляетКак прочитать
app.decorate()Экземплярapp.posts
app.decorateRequest()Каждый запросrequest.startTime
app.decorateReply()Каждый ответreply.имя
app.hasDecorator()—Проверить, есть ли декоратор

Частая ошибка

В Fastify 5 decorateRequest нельзя передать объект или массив как начальное значение — он оказался бы общим для всех запросов, и Fastify выдаст ошибку при старте:

// src/plugins/timing.js
app.decorateRequest('meta', { name: '' }); // ошибка

Передайте null и записывайте объект в каждом запросе отдельно.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.