Хуки
Хук — функция, которую Fastify вызывает на определённом этапе жизни запроса или приложения. Хуки заменяют middleware из других фреймворков: в них проверяют доступ, добавляют заголовки, пишут логи.
Этапы запроса
| Хук | Когда вызывается | Пример задачи |
|---|---|---|
onRequest | Сразу после получения запроса | Засечь время, проверить токен |
preValidation | Перед проверкой схемы | Подготовить данные |
preHandler | Перед обработчиком маршрута | Проверить права |
onSend | Перед отправкой ответа | Изменить ответ, добавить заголовок |
onResponse | После отправки ответа | Записать статистику |
Хуки приложения: onReady — после загрузки всех плагинов, onClose — при остановке сервера.
onRequest
Добавьте хук в плагин src/plugins/timing.js из прошлого урока:
// src/plugins/timing.js
import fp from 'fastify-plugin';
async function timing(app) {
app.decorateRequest('startTime', 0);
app.addHook('onRequest', async (request) => {
request.startTime = Date.now();
});
}
export default fp(timing);Теперь у каждого запроса в request.startTime записано время его начала.
onSend
Хук onSend получает третий аргумент — готовое тело ответа. Добавьте его в тот же плагин:
// src/plugins/timing.js
app.addHook('onSend', async (request, reply, payload) => {
reply.header('x-response-time', `${Date.now() - request.startTime}ms`);
return payload;
});curl -i http://localhost:3000/posts покажет заголовок x-response-time: 2ms. Хук обязан вернуть payload — то, что он вернёт, и уйдёт клиенту.
Хук одного маршрута
Хук можно повесить не на всё приложение, а на один маршрут — в его опциях:
// src/routes/posts.js
async function checkAdminHeader(request, reply) {
if (request.headers['x-admin'] !== 'yes') {
return reply.code(403).send({ error: 'Доступ запрещён' });
}
}
app.delete('/posts/:id', { preHandler: checkAdminHeader }, async (request, reply) => {
return reply.code(204).send();
});DELETE /posts/1 без заголовка x-admin: yes вернёт 403, и обработчик не выполнится. Настоящую проверку через токен покажем в уроке об авторизации.
onClose
onClose вызывается при app.close() — там освобождают ресурсы:
// src/plugins/timing.js
app.addHook('onClose', async () => {
app.log.info('Сервер останавливается');
});При остановке через app.close() в логе появится эта строка. В уроке о базе данных здесь будет закрываться соединение.
Область действия
Хук, добавленный в плагине без fastify-plugin, действует только на маршруты этого плагина. Так можно включить проверку для одной группы маршрутов.
Частая ошибка
Если хук отправил ответ через reply.send(), но не вернул reply, Fastify продолжит обработку и вызовет обработчик маршрута. В асинхронном хуке пишите return reply.code(403).send(...), как в примере выше, или бросайте ошибку через throw.