Создание строго типизированных middleware на TypeScript для Express.js

Express.js — популярный веб-фреймворк для Node.js, который позволяет создавать серверные приложения с использованием middleware. Middleware — это функции, обрабатывающие запросы перед их передачей конечным обработчикам. В TypeScript можно строго типизировать middleware, что помогает избежать ошибок и упрощает поддержку кода. В этой статье мы рассмотрим, как создать строго типизированные middleware на TypeScript для Express.js.
Что такое middleware в Express.js?
Middleware — это функции, которые выполняются между получением HTTP-запроса сервером и отправкой ответа клиенту. Эти функции имеют доступ к объектам запроса (req
), ответа (res
) и следующей функции (next
).
Пример базового middleware:
import { Request, Response, NextFunction } from "express";
function exampleMiddleware(req: Request, res: Response, next: NextFunction): void {
console.log("Middleware выполнен");
next();
}
Middleware в этом примере просто выводит сообщение в консоль и передаёт управление следующей функции.
Типизация middleware с использованием TypeScript
TypeScript позволяет строго типизировать параметры middleware, чтобы избежать ошибок при обработке данных. Рассмотрим пример:
import { Request, Response, NextFunction } from "express";
// Интерфейс для типизации параметров запроса
interface TypedRequestBody<T> extends Request {
body: T;
}
// Middleware для проверки данных в теле запроса
function validateBodyMiddleware<T>(schema: (body: T) => boolean) {
return (req: TypedRequestBody<T>, res: Response, next: NextFunction): void => {
if (!schema(req.body)) {
res.status(400).send("Invalid request body");
return;
}
next();
};
}
// Пример использования:
const validateUserMiddleware = validateBodyMiddleware<{ username: string; password: string }>(
(body) => !!body.username && !!body.password
);
Объяснение кода:
TypedRequestBody<T>
: Наследует объектRequest
и переопределяет типbody
, чтобы он соответствовал указанному типуT
.validateBodyMiddleware
: Универсальная функция, которая принимает схему валидации и возвращает middleware для проверки данных.validateUserMiddleware
: Пример использования для проверки данных пользователя.
В больших приложениях может возникнуть необходимость динамического подключения middleware в зависимости от конфигурации или маршрута. Подробнее о типизации динамических модулей можно прочитать в статье Типизация динамических модулей в TypeScript.
Практическое применение строго типизированных middleware
Строгая типизация middleware не только помогает избежать ошибок, но и делает код более понятным и удобным в использовании. Рассмотрим несколько примеров, где middleware строго типизируются с использованием TypeScript, и разберём, как и где эта типизация обеспечивает безопасность кода.
1. Middleware для проверки авторизации
import { Request, Response, NextFunction } from "express";
// Интерфейс для типизации данных пользователя
interface User {
id: string;
role: string;
}
// Интерфейс для запроса с данными пользователя
interface AuthenticatedRequest extends Request {
user?: User;
}
// Строго типизированное middleware для авторизации
function authenticateMiddleware(
req: AuthenticatedRequest,
res: Response,
next: NextFunction
): void {
const token = req.headers.authorization;
if (!token) {
res.status(401).send("Unauthorized");
return;
}
// В реальной системе здесь проводится проверка токена
req.user = { id: "123", role: "admin" }; // Моделируем добавление пользователя
next();
}
interface AuthenticatedRequest
: Расширяет стандартныйRequest
, добавляя строго типизированное полеuser
, содержащее объект пользователя с идентификатором и ролью.req: AuthenticatedRequest
: Типизирует объект запроса, чтобы гарантировать доступ к полюuser
, добавляемому в middleware.- Использование
Response
иNextFunction
: Эти типы, импортируемые из Express, обеспечивают стандартную типизацию остальных параметров.
2. Middleware для добавления уникального идентификатора запроса
import { Request, Response, NextFunction } from "express";
import { v4 as uuidv4 } from "uuid";
// Расширяем Request, добавляя поле requestId
interface RequestWithId extends Request {
requestId: string;
}
// Middleware для генерации идентификатора запроса
function requestIdMiddleware(
req: RequestWithId,
res: Response,
next: NextFunction
): void {
req.requestId = uuidv4();
next();
}
Объяснение типизации:
RequestWithId
: Расширяет стандартный объект запроса, добавляя строго типизированное полеrequestId
с типомstring
.req: RequestWithId
: Гарантирует, что после выполнения middleware полеrequestId
будет доступно в любом обработчике запроса.- Middleware выполняет добавление уникального идентификатора к каждому запросу, улучшая трассировку.
Эти примеры демонстрируют, как строгая типизация middleware делает код безопаснее, надёжнее и удобнее для работы в крупных проектах.
Преимущества строгой типизации
Использование TypeScript для типизации middleware даёт следующие преимущества:
- Сокращение числа ошибок, связанных с неправильными параметрами.
- Улучшение автодополнения в IDE.
- Упрощение командной разработки благодаря явному контракту типов.