UNPKG

@the-teacher/the-router

Version:

Simple router for Express.js, making routes and actions easy to manage.

406 lines (310 loc) 15.6 kB
# `The Router` Простое и мощное решение для маршрутизации в приложениях на `Express.js`, которое предоставляет чистый и интуитивно понятный способ организации маршрутов и действий. ## Возможности - Простой синтаксис определения маршрутов (похож на фреймворк Rails) - Подход, основанный на действиях (похож на фреймворк Hanami) - Каждое действие в отдельном файле для лучшей поддерживаемости - Группировка маршрутов для улучшенной организации - Автоматическая загрузка действий ## Установка ```bash npm install @the-teacher/the-router ``` ```bash yarn add @the-teacher/the-router ``` ```bash pnpm add @the-teacher/the-router ``` ## Использование ### Базовые маршруты `routes/index.ts` ```ts import { root, get, post, getRouter, routeScope as scope, } from "@the-teacher/the-router"; // Определение корневого маршрута root("index/index"); // Использует src/actions/index/indexAction.ts // Определение GET и POST маршрутов get("/users", "users/show"); // Использует src/actions/users/showAction.ts post("/users", "users/create"); // Использует src/actions/users/createAction.ts // Определение сгруппированных маршрутов scope("admin", () => { get("/users", "admin/users/create"); // Использует src/actions/admin/users/createAction.ts post("/users", "admin/users/update"); // Использует src/actions/admin/users/updateAction.ts }); ``` ### Структура файлов действий Каждое действие определяется в своём собственном файле и **должно экспортировать функцию `perform`**: ```bash src/ actions/ index/ indexAction.ts # обработчик для root("index/index") users/ showAction.ts # обработчик для get("/users", "users/show") createAction.ts # обработчик для post("/users", "users/create") admin/ users/ listAction.ts # обработчик для get("/users", "admin/users/list") в scope admin ``` Пример файла действия: ```typescript // src/actions/users/showAction.ts import { Request, Response } from "express"; // perform - обязательный метод для каждого действия export const perform = (req: Request, res: Response) => { res.json({ message: "Список пользователей" }); }; ``` ### Группировка маршрутов Группируйте связанные маршруты под общим префиксом: ```ts scope("admin", () => { get("/users", "admin/users/list"); // Использует src/actions/admin/users/listAction.ts post("/users", "admin/users/create"); // Использует src/actions/admin/users/createAction.ts }); ``` ### Маршруты с Middleware Вы можете добавлять middleware к любому маршруту: ```ts import { authenticate } from "./middlewares/auth"; import { validateUser } from "./middlewares/validation"; // Один middleware get("/users/:id", [authenticate], "users/show"); // Несколько middleware в порядке выполнения post("/users", [authenticate, validateUser], "users/create"); // Корневой маршрут с middleware root([authenticate], "index/index"); // Простые маршруты без middleware get("/about", "pages/about"); post("/contact", "pages/contact"); // Middleware в сгруппированных маршрутах scope("admin", [authenticate], () => { // Эти маршруты наследуют аутентификацию из scope get("/users", "users/show"); post("/users", "users/create"); // Дополнительный middleware для конкретного маршрута post("/users/:id", [validateUser], "users/update"); }); ``` ### Группировка маршрутов с Middleware Вы можете добавлять middleware как к отдельным маршрутам, так и ко всей группе маршрутов: ```ts import { authenticate } from "./middlewares/auth"; import { validateUser } from "./middlewares/validation"; import { logRequest } from "./middlewares/logging"; // Применить middleware ко всем маршрутам в группе scope("admin", [authenticate], () => { // Эти маршруты будут требовать аутентификации get("/users", "users/index"); post("/users", "users/create"); // Этот маршрут будет требовать и аутентификации, и валидации post("/users/:id", [validateUser], "users/update"); }); // Комбинирование нескольких middleware для группы scope("api", [authenticate, logRequest], () => { get("/stats", "stats/index"); get("/health", "health/check"); }); // Простая группа без middleware scope("public", () => { get("/about", "pages/about"); get("/contact", "pages/contact"); }); ``` Middleware, указанные вторым параметром, будут применяться ко всем маршрутам внутри этой группы. При этом вы можете добавлять дополнительные middleware к конкретным маршрутам, которые будут выполняться после middleware группы. ### Структура файлов приложения: ```bash src/ index.ts routes/ index.ts actions/ index/ indexAction.ts users/ showAction.ts createAction.ts updateAction.ts posts/ showAction.ts createAction.ts admin/ users/ listAction.ts createAction.ts posts/ listAction.ts updateAction.ts ``` Пример маршрутов, соответствующих этой структуре: ```ts import { root, get, post, routeScope as scope } from "@the-teacher/the-router"; // Корневой и базовые маршруты root("index/index"); // -> src/actions/index/indexAction.ts get("/users", "users/show"); // -> src/actions/users/showAction.ts post("/users", "users/create"); // -> src/actions/users/createAction.ts get("/posts", "posts/show"); // -> src/actions/posts/showAction.ts post("/posts", "posts/create"); // -> src/actions/posts/createAction.ts // Административная часть scope("admin", () => { get("/users", "users/list"); // -> src/actions/admin/users/listAction.ts post("/users", "users/create"); // -> src/actions/admin/users/createAction.ts get("/posts", "posts/list"); // -> src/actions/admin/posts/listAction.ts post("/posts", "posts/update"); // -> src/actions/admin/posts/updateAction.ts }); ``` Это создаст маршруты: - GET `/` -> `src/actions/index/indexAction.ts` - GET `/users` -> `src/actions/users/showAction.ts` - POST `/users` -> `src/actions/users/createAction.ts` - GET `/posts` -> `src/actions/posts/showAction.ts` - POST `/posts` -> `src/actions/posts/createAction.ts` - GET `/admin/users` -> `src/actions/admin/users/listAction.ts` - POST `/admin/users` -> `src/actions/admin/users/createAction.ts` - GET `/admin/posts` -> `src/actions/admin/posts/listAction.ts` - POST `/admin/posts` -> `src/actions/admin/posts/updateAction.ts` ### Группировка маршрутов Группируйте связанные маршруты под общим префиксом: ```ts scope("admin", () => { get("/users", "users/list"); // -> src/actions/admin/users/listAction.ts post("/users", "users/create"); // -> src/actions/admin/users/createAction.ts }); ``` ### Маршруты с параметрами Маршруты могут включать динамические параметры: ```ts // Базовые маршруты с параметрами get("/users/:id", "users/show"); // -> /users/123 get("/posts/:id/comments", "posts/comments"); // -> /posts/456/comments // Параметры с middleware get("/users/:id", [authenticate], "users/show"); // Несколько параметров get("/posts/:postId/comments/:commentId", "comments#show"); ``` ### Порядок маршрутов Порядок определения маршрутов имеет значение. Более специфичные маршруты должны быть определены перед более общими: ```ts // ✅ Правильный порядок get("/posts/featured", "posts/featured"); // Сначала специфичный маршрут get("/posts/:id", "posts/show"); // Затем общий маршрут // ❌ Неправильный порядок - "/posts/featured" никогда не будет достигнут get("/posts/:id", "posts/show"); // Общий маршрут перехватывает все get("/posts/featured", "posts/featured"); // Никогда не сработает ``` ### Организация Middleware При использовании нескольких middleware рекомендуется группировать их в переменные для лучшей поддерживаемости: ```ts // Группировка связанных middleware const authMiddlewares = [authenticate, checkRole]; const validationMiddlewares = [validateUser, sanitizeInput]; // Использование групп middleware в маршрутах get("/users", authMiddlewares, "users/index"); post("/users", [...authMiddlewares, ...validationMiddlewares], "users/create"); // В сгруппированных маршрутах const adminMiddlewares = [authenticate, requireAdmin, logAccess]; scope("admin", adminMiddlewares, () => { get("/users", "users/list"); // Дополнительные middleware для конкретных маршрутов const userUpdateMiddlewares = [validateUser]; post("/users/:id", userUpdateMiddlewares, "users/update"); }); ``` ### API Reference Базовое использование: - `root(scopeAction)`: Определяет корневой маршрут (`/`) - `get(path, scopeAction)`: Определяет GET маршрут - `post(path, scopeAction)`: Определяет POST маршрут - `put(path, scopeAction)`: Определяет PUT маршрут - `patch(path, scopeAction)`: Определяет PATCH маршрут - `destroy(path, scopeAction)`: Определяет DELETE маршрут - `options(path, scopeAction)`: Определяет OPTIONS маршрут - `head(path, scopeAction)`: Определяет HEAD маршрут - `all(path, scopeAction)`: Определяет маршрут для всех HTTP методов - `scope(prefix, callback)`: Группирует маршруты под общим префиксом С middleware: - `root(middlewares[], scopeAction)`: Определяет корневой маршрут с middleware - `get(path, middlewares[], scopeAction)`: Определяет GET маршрут с middleware - `post(path, middlewares[], scopeAction)`: Определяет POST маршрут с middleware - `put(path, middlewares[], scopeAction)`: Определяет PUT маршрут с middleware - `patch(path, middlewares[], scopeAction)`: Определяет PATCH маршрут с middleware - `destroy(path, middlewares[], scopeAction)`: Определяет DELETE маршрут с middleware - `options(path, middlewares[], scopeAction)`: Определяет OPTIONS маршрут с middleware - `head(path, middlewares[], scopeAction)`: Определяет HEAD маршрут с middleware - `all(path, middlewares[], scopeAction)`: Определяет маршрут для всех HTTP методов с middleware - `scope(prefix, middlewares[], callback)`: Группирует маршруты с middleware Примеры: ```ts // Базовое использование root("index/index"); get("/users", "users/show"); post("/users", "users/create"); put("/users/:id", "users/update"); patch("/users/:id", "users/patch"); destroy("/users/:id", "users/delete"); options("/users", "users/options"); head("/users", "users/head"); all("/api", "api/handle"); scope("admin", () => { /* маршруты */ }); // С middleware const authMiddlewares = [authenticate, logRequest]; root([authenticate], "index/index"); get("/users", authMiddlewares, "users/show"); put("/users/:id", authMiddlewares, "users/update"); scope("admin", authMiddlewares, () => { /* маршруты */ }); ``` ### Маршруты с регулярными выражениями Вы можете использовать регулярные выражения для путей маршрутов: ```ts // Сопоставление путей, заканчивающихся на 'fly' get(/.*fly$/, "insects#list"); // Совпадает с: /butterfly, /dragonfly get(/^\/api\/v\d+\/.*$/, "api#handle"); // Совпадает с: /api/v1/users, /api/v2/posts // Маршруты с регулярными выражениями и middleware get(/^\/secure\/.*$/, [authenticate], "secure#handle"); // Порядок важен и для маршрутов с регулярными выражениями get(/^\/api\/v1\/users$/, "users/list"); // Сначала специфичный маршрут get(/^\/api\/v1\/.*$/, "api/handle"); // Затем общий маршрут ``` Примечание: При использовании регулярных выражений путь передается в `Express.js` как есть, без какой-либо нормализации. ### Ресурсные маршруты Подобно Ruby on Rails, вы можете определить набор RESTful маршрутов для ресурса: ```ts resources("posts"); ``` Это создаст следующие маршруты: - `GET /posts` -> `src/actions/posts/indexAction.ts` - `GET /posts/new` -> `src/actions/posts/newAction.ts` - `POST /posts` -> `src/actions/posts/createAction.ts` - `GET /posts/:id` -> `src/actions/posts/showAction.ts` - `GET /posts/:id/edit` -> `src/actions/posts/editAction.ts` - `PUT /posts/:id` -> `src/actions/posts/updateAction.ts` - `PATCH /posts/:id` -> `src/actions/posts/updateAction.ts` - `DELETE /posts/:id` -> `src/actions/posts/destroyAction.ts` Вы можете добавить middleware для всех маршрутов ресурса: ```ts const postMiddlewares = [authenticate, logRequest]; resources("posts", postMiddlewares); ``` Ресурсы также можно группировать: ```ts scope("admin", [authenticate], () => { resources("posts"); // Маршруты будут начинаться с /admin resources("users"); // Маршруты будут начинаться с /admin }); ``` Это создаст маршруты вида `/admin/posts`, `/admin/posts/:id` и т.д. ### License MIT. ### Author Ilya N. Zykin | [the-teacher](https://github.com/the-teacher)