Как Fastify обрабатывает асинхронные обработчики маршрутов по сравнению с Express?
Fastify нативно поддерживает async/await в обработчиках: брошенный Error автоматически превращается в JSON-ответ с кодом 500. Express требует явного вызова next(err), иначе ошибка «провалится» и сервер зависнет.
Как Fastify обрабатывает async-обработчики
В Fastify обработчик маршрута может быть обычной async-функцией, возвращающей значение. Fastify сам сериализует возвращаемое значение через fast-json-stringify по схеме маршрута и отправляет ответ. Если async-функция выбрасывает исключение, Fastify перехватывает его через внутренний try/catch и передаёт в setErrorHandler. Явно вызывать reply.send() не нужно — хотя это тоже допустимо.
Сравнение с Express
В Express async-обработчик не перехватывается автоматически. Если внутри async (req, res, next) => {} выбрасывается ошибка, Express «не видит» её, если не вызвать next(err) вручную или не обернуть весь обработчик в try/catch. Это классический источник утечек запросов (hanging requests) — сервер просто не отвечает клиенту.
// Fastify: бросить достаточно
fastify.get("/users/:id", async (request, reply) => {
const user = await db.findUserById(request.params.id);
if (!user) throw fastify.httpErrors.notFound("User not found");
return user; // автоматически сериализуется
});
// Express: нужен явный next(err)
app.get("/users/:id", async (req, res, next) => {
try {
const user = await db.findUserById(req.params.id);
if (!user) return res.status(404).json({ error: "Not found" });
res.json(user);
} catch (err) {
next(err); // без этого запрос зависнет
}
});
Lifecycle и hook-интеграция
Fastify выполняет async-обработчики внутри строгого lifecycle: onRequest → preParsing → preValidation → preHandler → handler → preSerialization → onSend → onResponse. Каждый hook тоже может быть async-функцией и выбрасывать ошибки. Хук onError позволяет перехватывать ошибки до отправки ответа — например, для логирования или трансформации.
fastify.setErrorHandler(async (error, request, reply) => {
request.log.error({ err: error, reqId: request.id }, "Unhandled error");
const statusCode = error.statusCode ?? 500;
return reply.status(statusCode).send({
error: statusCode < 500 ? error.message : "Internal Server Error",
});
});
Параллельные async-операции
Поскольку Fastify не блокирует event loop между хуками, несколько параллельных запросов обрабатываются конкурентно. Важно: если в async-обработчике используется reply.hijack(), Fastify полностью передаёт управление разработчику — автоматической сериализации и перехвата ошибок не будет.
Подводные камни
- Возврат
undefinedиз async-обработчика безreply.send()отправит пустой 200 — часто нежелательно; лучше всегда возвращать явное значение или использовать reply. - Использование
reply.send()и возврата значения одновременно приведёт к ошибке «Reply already sent». - Ошибки в
onResponse-хуке не могут изменить ответ — он уже отправлен; перехватывать критические ошибки нужно вonSend. - В Express без
express-async-errorsили ручного try/catch async-ошибки «глотаются» — сервер виснет без ответа клиенту. - Fastify fast-json-stringify сериализует только поля, описанные в response schema; лишние поля удаляются — это фича, но может удивить.
- Не путать
throw new Error()сthrow fastify.httpErrors.badRequest(): первое даёт 500, второе — 400 с правильным statusCode. reply.hijack()отключает автоматику — при использовании SSE или WebSocket нужно самостоятельно завершать соединения в onClose.- Тяжёлые синхронные операции внутри async-обработчика блокируют event loop для всех параллельных запросов.
Common mistakes
- Дает общий ответ про Node.js и не называет конкретные API Fastify.
- Не объясняет, где в lifecycle находится async handlers в Fastify и Express.
- Не разделяет validation, authorization, business logic и persistence.
- Игнорирует ошибки, лимиты входных данных, observability и тестирование.
What the interviewer is testing
- Может объяснить async handlers в Fastify и Express на примере кода.
- Называет ключевые API: async handler, throw.
- Использует точные API Fastify, а не вымышленные hooks/decorators/methods.
- Видит production-риски: безопасность, отказоустойчивость, логирование и тесты.