@ismael1361/router 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +988 -0
- package/dist/HandleError.d.ts +78 -0
- package/dist/HandleError.d.ts.map +1 -0
- package/dist/handler.d.ts +114 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +153 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/router.d.ts +416 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/setupTests.d.ts +3 -0
- package/dist/setupTests.d.ts.map +1 -0
- package/dist/type.d.ts +125 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/utils.d.ts +123 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { Request, Response, ExpressRouter, MiddlewareFC } from "./type";
|
|
2
|
+
import { Router } from "./router";
|
|
3
|
+
/**
|
|
4
|
+
* Representa um construtor de cadeia de middlewares.
|
|
5
|
+
* Esta classe é a base para criar sequências de middlewares de forma fluente,
|
|
6
|
+
* permitindo que os tipos de requisição e resposta sejam estendidos a cada passo.
|
|
7
|
+
*
|
|
8
|
+
* @template Rq O tipo de requisição acumulado na cadeia de middlewares.
|
|
9
|
+
* @template Rs O tipo de resposta acumulado na cadeia de middlewares.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RequestMiddleware<Rq extends Request = Request, Rs extends Response = Response> {
|
|
12
|
+
readonly router: ExpressRouter;
|
|
13
|
+
/** A lista de middlewares acumulados. */
|
|
14
|
+
middlewares: MiddlewareFC<any, any>[];
|
|
15
|
+
/**
|
|
16
|
+
* @param {MiddlewareFC<Rq, Rs>} [callback] - O middleware inicial para adicionar à cadeia.
|
|
17
|
+
* @param {MiddlewareFC<any, any>[]} [middlewares=[]] - Uma lista de middlewares pré-existentes para iniciar a cadeia.
|
|
18
|
+
*/
|
|
19
|
+
constructor(callback: MiddlewareFC<Rq, Rs> | undefined, middlewares?: MiddlewareFC<any, any>[], router?: ExpressRouter);
|
|
20
|
+
/**
|
|
21
|
+
* Adiciona um novo middleware à cadeia.
|
|
22
|
+
*
|
|
23
|
+
* @template Req O tipo de requisição que este novo middleware adiciona.
|
|
24
|
+
* @template Res O tipo de resposta que este novo middleware adiciona.
|
|
25
|
+
* @param {MiddlewareFC<Rq & Req, Rs & Res>} callback O middleware a ser adicionado.
|
|
26
|
+
* @returns {RequestMiddleware<Rq & Req, Rs & Res>} Uma nova instância de `RequestMiddleware` com a cadeia estendida.
|
|
27
|
+
*/
|
|
28
|
+
middleware<Req extends Request = Request, Res extends Response = Response>(callback: MiddlewareFC<Rq & Req, Rs & Res>): RequestMiddleware<Rq & Req, Rs & Res>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Um construtor de roteadores com middlewares compartilhados.
|
|
32
|
+
*
|
|
33
|
+
* Esta classe permite construir uma base de middlewares de forma fluente e com segurança de tipos.
|
|
34
|
+
* Após configurar os middlewares desejados, você pode usar o método `.route()` para criar
|
|
35
|
+
* roteadores específicos (sub-rotas) que herdam automaticamente todos os middlewares e
|
|
36
|
+
* suas respectivas tipagens de requisição e resposta.
|
|
37
|
+
*
|
|
38
|
+
* Isso é útil para agrupar rotas que compartilham a mesma lógica de autenticação,
|
|
39
|
+
* logging ou qualquer outro pré-processamento, garantindo que os tipos sejam consistentes.
|
|
40
|
+
*
|
|
41
|
+
* @template Rq O tipo de requisição acumulado na cadeia de middlewares.
|
|
42
|
+
* @template Rs O tipo de resposta acumulado na cadeia de middlewares.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* import express, { Request, Response, NextFunction } from "express";
|
|
46
|
+
* import { MiddlewareRouter, MiddlewareFC } from "./middleware"; // Ajuste o caminho
|
|
47
|
+
*
|
|
48
|
+
* // 1. Defina os tipos e middlewares que estendem a requisição
|
|
49
|
+
* interface AuthRequest { user: { id: number; role: string }; }
|
|
50
|
+
* const authMiddleware: MiddlewareFC<AuthRequest> = (req, res, next) => {
|
|
51
|
+
* // Em um app real, validaria um token e buscaria o usuário
|
|
52
|
+
* req.user = { id: 1, role: "admin" };
|
|
53
|
+
* next();
|
|
54
|
+
* };
|
|
55
|
+
*
|
|
56
|
+
* interface LoggedRequest { log: (message: string) => void; }
|
|
57
|
+
* const loggerMiddleware: MiddlewareFC<LoggedRequest> = (req, res, next) => {
|
|
58
|
+
* req.log = (message) => console.log(`[${new Date().toISOString()}] ${message}`);
|
|
59
|
+
* next();
|
|
60
|
+
* };
|
|
61
|
+
*
|
|
62
|
+
* // 2. Crie uma base de roteamento com os middlewares
|
|
63
|
+
* const baseRouter = new MiddlewareRouter(authMiddleware)
|
|
64
|
+
* .middleware(loggerMiddleware)
|
|
65
|
+
*
|
|
66
|
+
* // 3. Crie sub-rotas a partir da base. Elas herdarão os middlewares.
|
|
67
|
+
* const usersRouter = baseRouter.route("/users");
|
|
68
|
+
* const postsRouter = baseRouter.route("/posts");
|
|
69
|
+
*
|
|
70
|
+
* // 4. Defina os handlers. `req` terá os tipos `AuthRequest & LoggedRequest`.
|
|
71
|
+
* usersRouter.get("/:id").handler((req, res) => {
|
|
72
|
+
* req.log(`Buscando usuário com ID: ${req.params.id}`);
|
|
73
|
+
* // `req.user` está disponível e tipado
|
|
74
|
+
* res.json({ id: req.params.id, requester: req.user });
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* postsRouter.get("/").handler((req, res) => {
|
|
78
|
+
* req.log("Listando posts");
|
|
79
|
+
* // `req.user` também está disponível aqui
|
|
80
|
+
* if (req.user.role !== 'admin') {
|
|
81
|
+
* return res.status(403).send("Acesso negado");
|
|
82
|
+
* }
|
|
83
|
+
* res.json([{ id: 1, title: "Post de Admin" }]);
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // 5. Use os roteadores no seu app Express
|
|
87
|
+
* const app = express();
|
|
88
|
+
* // O roteador principal que contém as sub-rotas é o `baseRouter.router`
|
|
89
|
+
* app.use("/api/v1", baseRouter.router);
|
|
90
|
+
*
|
|
91
|
+
* app.listen(3000, () => console.log("Servidor rodando na porta 3000"));
|
|
92
|
+
*/
|
|
93
|
+
export declare class MiddlewareRouter<Rq extends Request = Request, Rs extends Response = Response> extends RequestMiddleware<Rq, Rs> {
|
|
94
|
+
/**
|
|
95
|
+
* Adiciona um novo middleware à cadeia de construção.
|
|
96
|
+
*
|
|
97
|
+
* Este método é imutável: ele retorna uma **nova instância** de `MiddlewareRouter`
|
|
98
|
+
* com o middleware adicionado, permitindo o encadeamento seguro. A tipagem dos
|
|
99
|
+
* objetos `Request` e `Response` é aprimorada para refletir as modificações
|
|
100
|
+
* feitas pelo novo middleware.
|
|
101
|
+
*
|
|
102
|
+
* @template Req O tipo de `Request` que o novo middleware adiciona ou modifica.
|
|
103
|
+
* @template Res O tipo de `Response` que o novo middleware adiciona ou modifica.
|
|
104
|
+
* @param {MiddlewareFC<Rq & Req, Rs & Res>} callback A função de middleware a ser adicionada.
|
|
105
|
+
* @returns {MiddlewareRouter<Rq & Req, Rs & Res>} Uma nova instância de `MiddlewareRouter` com a cadeia estendida.
|
|
106
|
+
*/
|
|
107
|
+
middleware<Req extends Request = Request, Res extends Response = Response>(callback: MiddlewareFC<Rq & Req, Rs & Res>): MiddlewareRouter<Rq & Req, Rs & Res>;
|
|
108
|
+
/**
|
|
109
|
+
* Cria um novo sub-roteador (`Router`) montado em um prefixo de caminho específico.
|
|
110
|
+
*
|
|
111
|
+
* O roteador retornado herda todos os middlewares (e suas tipagens) que foram
|
|
112
|
+
* configurados nesta cadeia de `MiddlewareRouter`. É o principal método para
|
|
113
|
+
* criar grupos de rotas que compartilham uma configuração base.
|
|
114
|
+
*
|
|
115
|
+
* @param {string} path O prefixo do caminho para o sub-roteador.
|
|
116
|
+
* @returns {Router<Rq, Rs>} Uma nova instância de `Router` para definir as rotas finais.
|
|
117
|
+
* @see MiddlewareRouter para um exemplo de uso completo.
|
|
118
|
+
*/
|
|
119
|
+
route(path: string): Router<Rq, Rs>;
|
|
120
|
+
/**
|
|
121
|
+
* Monta um sub-roteador existente na raiz do roteador base.
|
|
122
|
+
*
|
|
123
|
+
* Este método é usado para compor a aplicação anexando um módulo de rotas
|
|
124
|
+
* pré-construído (uma instância de `Router` ou `express.Router`).
|
|
125
|
+
*
|
|
126
|
+
* **Importante:** Diferente do método `.route()`, os middlewares configurados
|
|
127
|
+
* na cadeia do `MiddlewareRouter` **não são herdados** pelo roteador que está
|
|
128
|
+
* sendo montado com `.by()`. Ele é útil para anexar roteadores que
|
|
129
|
+
* não devem compartilhar o mesmo contexto de middleware (por exemplo, rotas públicas).
|
|
130
|
+
*
|
|
131
|
+
* @param {Router | ExpressRouter} router - A instância do roteador a ser montada.
|
|
132
|
+
* @returns {this} A instância atual de `MiddlewareRouter`, permitindo o encadeamento de chamadas.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // RequestMiddleware de autenticação
|
|
136
|
+
* const authMiddleware = (req, res, next) => {
|
|
137
|
+
* req.user = { id: 1 };
|
|
138
|
+
* next();
|
|
139
|
+
* };
|
|
140
|
+
*
|
|
141
|
+
* // Roteador base com autenticação
|
|
142
|
+
* const api = new MiddlewareRouter(authMiddleware);
|
|
143
|
+
*
|
|
144
|
+
* // Roteador de status público (não deve ter auth)
|
|
145
|
+
* const statusRouter = new Router();
|
|
146
|
+
* statusRouter.get("/status").handler((req, res) => res.send("Service is up"));
|
|
147
|
+
*
|
|
148
|
+
* // Monta o roteador público usando .by()
|
|
149
|
+
* api.by(statusRouter);
|
|
150
|
+
*/
|
|
151
|
+
by(router: Router | ExpressRouter): this;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIlC;;;;;;;GAOG;AACH,qBAAa,iBAAiB,CAAC,EAAE,SAAS,OAAO,GAAG,OAAO,EAAE,EAAE,SAAS,QAAQ,GAAG,QAAQ;IAQU,QAAQ,CAAC,MAAM,EAAE,aAAa;IAPlI,yCAAyC;IAClC,WAAW,EAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IAE7C;;;OAGG;gBACS,QAAQ,EAAE,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,SAAS,EAAE,WAAW,GAAE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,EAAO,EAAW,MAAM,GAAE,aAAgC;IAKrJ;;;;;;;OAOG;IACH,UAAU,CAAC,GAAG,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,QAAQ,GAAG,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,GAAG,iBAAiB,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC;CAI7J;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,qBAAa,gBAAgB,CAAC,EAAE,SAAS,OAAO,GAAG,OAAO,EAAE,EAAE,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC;IAC5H;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,GAAG,SAAS,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,QAAQ,GAAG,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,GAAG,gBAAgB,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC;IAK5J;;;;;;;;;;OAUG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC;IAInC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;CAIxC"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import type swaggerJSDoc from "swagger-jsdoc";
|
|
2
|
+
import { ExpressRouter, HandlerFC, MiddlewareFC, RouterMethods, Request, Response } from "./type";
|
|
3
|
+
import { RequestHandler, PreparedHandler } from "./handler";
|
|
4
|
+
/**
|
|
5
|
+
* A classe `Router` é um wrapper em torno do roteador do Express, oferecendo uma API fluente
|
|
6
|
+
* e encadeável para a definição de rotas. Ela aprimora a experiência de desenvolvimento com
|
|
7
|
+
* segurança de tipos e geração de documentação OpenAPI/Swagger integrada.
|
|
8
|
+
*
|
|
9
|
+
* @template Rq - O tipo base para o objeto de requisição (request) em todas as rotas deste roteador.
|
|
10
|
+
* @template Rs - O tipo base para o objeto de resposta (response) em todas as rotas.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* import express, { Request, Response } from "express";
|
|
14
|
+
* import { Router } from "./router"; // Ajuste o caminho do import conforme sua estrutura.
|
|
15
|
+
* import swaggerUi from "swagger-ui-express";
|
|
16
|
+
*
|
|
17
|
+
* // 1. Crie uma nova instância do Router.
|
|
18
|
+
* const userRouter = new Router();
|
|
19
|
+
*
|
|
20
|
+
* // 2. Defina uma rota com um manipulador e documentação.
|
|
21
|
+
* userRouter
|
|
22
|
+
* .get("/:id")
|
|
23
|
+
* .handler((req: Request<{ id: string }>, res: Response) => {
|
|
24
|
+
* const { id } = req.params;
|
|
25
|
+
* res.json({ id: Number(id), name: "John Doe" });
|
|
26
|
+
* })
|
|
27
|
+
* .doc({
|
|
28
|
+
* summary: "Obter um usuário pelo ID",
|
|
29
|
+
* tags: ["Usuários"],
|
|
30
|
+
* parameters: [
|
|
31
|
+
* {
|
|
32
|
+
* name: "id",
|
|
33
|
+
* in: "path",
|
|
34
|
+
* required: true,
|
|
35
|
+
* description: "O ID do usuário",
|
|
36
|
+
* schema: { type: "integer" },
|
|
37
|
+
* },
|
|
38
|
+
* ],
|
|
39
|
+
* responses: {
|
|
40
|
+
* "200": {
|
|
41
|
+
* description: "Detalhes do usuário.",
|
|
42
|
+
* content: {
|
|
43
|
+
* "application/json": {
|
|
44
|
+
* schema: {
|
|
45
|
+
* type: "object",
|
|
46
|
+
* properties: {
|
|
47
|
+
* id: { type: "integer" },
|
|
48
|
+
* name: { type: "string" },
|
|
49
|
+
* },
|
|
50
|
+
* },
|
|
51
|
+
* },
|
|
52
|
+
* },
|
|
53
|
+
* },
|
|
54
|
+
* "404": {
|
|
55
|
+
* description: "Usuário não encontrado",
|
|
56
|
+
* }
|
|
57
|
+
* },
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* // 3. Crie um aplicativo Express e use o roteador.
|
|
61
|
+
* const app = express();
|
|
62
|
+
* app.use(express.json());
|
|
63
|
+
*
|
|
64
|
+
* // A propriedade `.router` contém a instância do roteador Express, pronta para ser usada.
|
|
65
|
+
* app.use("/users", userRouter.router);
|
|
66
|
+
*
|
|
67
|
+
* // 4. (Opcional) Gere e sirva a documentação Swagger.
|
|
68
|
+
* const swaggerOptions = userRouter.getSwagger({
|
|
69
|
+
* openapi: "3.0.0",
|
|
70
|
+
* info: {
|
|
71
|
+
* title: "API de Usuários",
|
|
72
|
+
* version: "1.0.0",
|
|
73
|
+
* },
|
|
74
|
+
* });
|
|
75
|
+
* app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerOptions));
|
|
76
|
+
*
|
|
77
|
+
* app.listen(3000, () => {
|
|
78
|
+
* console.log("Servidor rodando em http://localhost:3000");
|
|
79
|
+
* console.log("Documentação da API em http://localhost:3000/api-docs");
|
|
80
|
+
* });
|
|
81
|
+
*/
|
|
82
|
+
export declare class Router<Rq extends Request = Request, Rs extends Response = Response> {
|
|
83
|
+
readonly middlewares: MiddlewareFC<any, any>[];
|
|
84
|
+
readonly router: ExpressRouter;
|
|
85
|
+
constructor(middlewares?: MiddlewareFC<any, any>[], router?: ExpressRouter);
|
|
86
|
+
/**
|
|
87
|
+
* Adiciona um middleware que será aplicado a todas as rotas definidas subsequentemente
|
|
88
|
+
* nesta cadeia de roteamento.
|
|
89
|
+
*
|
|
90
|
+
* Este método é imutável: ele retorna uma **nova instância** do `Router` com o middleware
|
|
91
|
+
* adicionado, permitindo o encadeamento seguro e a composição de diferentes conjuntos de middlewares.
|
|
92
|
+
* A tipagem dos objetos `Request` e `Response` é aprimorada para refletir as modificações
|
|
93
|
+
* feitas pelo middleware.
|
|
94
|
+
*
|
|
95
|
+
* @template Req - O tipo de `Request` que o middleware adiciona ou modifica.
|
|
96
|
+
* @template Res - O tipo de `Response` que o middleware adiciona ou modifica.
|
|
97
|
+
*
|
|
98
|
+
* @param {MiddlewareFC<Rq & Req, Rs & Res>} callback - A função de middleware a ser adicionada.
|
|
99
|
+
* Esta função pode modificar os objetos `req` e `res`, e suas tipagens serão propagadas
|
|
100
|
+
* para os manipuladores de rota subsequentes.
|
|
101
|
+
*
|
|
102
|
+
* @returns {Router<Rq & Req, Rs & Res>} Uma nova instância do `Router` com o middleware
|
|
103
|
+
* e os tipos de requisição/resposta atualizados.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* import { Router } from "./router";
|
|
107
|
+
* import { Request, Response, NextFunction } from "express";
|
|
108
|
+
*
|
|
109
|
+
* // Middleware de autenticação que adiciona 'user' ao objeto de requisição.
|
|
110
|
+
* interface AuthenticatedRequest {
|
|
111
|
+
* user: { id: number; name: string };
|
|
112
|
+
* }
|
|
113
|
+
*
|
|
114
|
+
* const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
|
115
|
+
* // Em um cenário real, você validaria um token aqui.
|
|
116
|
+
* (req as Request & AuthenticatedRequest).user = { id: 1, name: "Admin" };
|
|
117
|
+
* next();
|
|
118
|
+
* };
|
|
119
|
+
*
|
|
120
|
+
* const baseRouter = new Router();
|
|
121
|
+
* const authenticatedRouter = baseRouter.middleware<AuthenticatedRequest>(authMiddleware);
|
|
122
|
+
*
|
|
123
|
+
* authenticatedRouter.get("/profile").handler((req, res) => {
|
|
124
|
+
* // `req.user` está disponível e corretamente tipado.
|
|
125
|
+
* res.json({ message: `Bem-vindo, ${req.user.name}!` });
|
|
126
|
+
* });
|
|
127
|
+
*/
|
|
128
|
+
middleware<Req extends Request = Request, Res extends Response = Response>(callback: MiddlewareFC<Rq & Req, Rs & Res>): Router<Rq & Req, Rs & Res>;
|
|
129
|
+
/**
|
|
130
|
+
* Encapsula uma função de handler final e todos os middlewares encadeados anteriormente
|
|
131
|
+
* em uma única instância reutilizável de `PreparedHandler`.
|
|
132
|
+
*
|
|
133
|
+
* Este método é o ponto final para a criação de "controllers" ou "actions" modulares.
|
|
134
|
+
* Ele pega a lógica do handler e a combina com os middlewares definidos na cadeia do roteador
|
|
135
|
+
* (`.middleware(...)`), produzindo um objeto que pode ser passado para o método `.handler()`
|
|
136
|
+
* de uma definição de rota (por exemplo, `router.get(...).handler(controller)`).
|
|
137
|
+
*
|
|
138
|
+
* @template Req - Tipos de requisição adicionais inferidos a partir do handler.
|
|
139
|
+
* @template Res - Tipos de resposta adicionais inferidos a partir do handler.
|
|
140
|
+
* @param {HandlerFC<Rq & Req, Rs & Res>} callback - A função de handler final ou uma instância de `PreparedHandler` já existente. Se um `PreparedHandler` for fornecido, seus middlewares serão combinados com os middlewares da cadeia atual.
|
|
141
|
+
* @returns {PreparedHandler<Rq & Req, Rs & Res>} Uma nova instância de `PreparedHandler` que encapsula o handler e a cadeia completa de middlewares.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* // 1. Defina middlewares para autenticação e autorização.
|
|
145
|
+
* interface AuthRequest extends Request { user: { id: number; role: string }; }
|
|
146
|
+
* const authMiddleware: MiddlewareFC<AuthRequest> = (req, res, next) => {
|
|
147
|
+
* req.user = { id: 1, role: 'admin' }; // Simula a autenticação
|
|
148
|
+
* next();
|
|
149
|
+
* };
|
|
150
|
+
*
|
|
151
|
+
* const adminOnlyMiddleware: MiddlewareFC<AuthRequest> = (req, res, next) => {
|
|
152
|
+
* if (req.user.role !== 'admin') return res.status(403).send('Forbidden');
|
|
153
|
+
* next();
|
|
154
|
+
* };
|
|
155
|
+
*
|
|
156
|
+
* // 2. Defina o handler final que depende dos middlewares.
|
|
157
|
+
* const getDashboard: HandlerFC<AuthRequest> = (req, res) => {
|
|
158
|
+
* res.send(`Welcome, admin user ${req.user.id}`);
|
|
159
|
+
* };
|
|
160
|
+
*
|
|
161
|
+
* // 3. Crie um "construtor" de controller encadeando os middlewares.
|
|
162
|
+
* const controllerBuilder = new Router().middleware(authMiddleware).middleware(adminOnlyMiddleware);
|
|
163
|
+
*
|
|
164
|
+
* // 4. Use o método `.handler()` para criar o controller reutilizável.
|
|
165
|
+
* const getDashboardController = controllerBuilder.handler(getDashboard);
|
|
166
|
+
*
|
|
167
|
+
* // 5. Agora, `getDashboardController` pode ser usado em qualquer rota.
|
|
168
|
+
* const mainRouter = new Router();
|
|
169
|
+
* mainRouter.get('/admin/dashboard').handler(getDashboardController);
|
|
170
|
+
* // A rota acima aplicará automaticamente `authMiddleware` e `adminOnlyMiddleware`
|
|
171
|
+
* // antes de executar `getDashboard`.
|
|
172
|
+
*/
|
|
173
|
+
handler<Req extends Request = Request, Res extends Response = Response>(callback: HandlerFC<Rq & Req, Rs & Res>): PreparedHandler<Rq & Req, Rs & Res>;
|
|
174
|
+
/**
|
|
175
|
+
* Cria um manipulador de rota para requisições GET.
|
|
176
|
+
* @param {string} path O caminho da rota.
|
|
177
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
178
|
+
*/
|
|
179
|
+
get(path: string): RequestHandler<Rq, Rs>;
|
|
180
|
+
/**
|
|
181
|
+
* Cria um manipulador de rota para requisições POST.
|
|
182
|
+
* @param {string} path O caminho da rota.
|
|
183
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
184
|
+
*/
|
|
185
|
+
post(path: string): RequestHandler<Rq, Rs>;
|
|
186
|
+
/**
|
|
187
|
+
* Cria um manipulador de rota para requisições PUT.
|
|
188
|
+
* @param {string} path O caminho da rota.
|
|
189
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
190
|
+
*/
|
|
191
|
+
put(path: string): RequestHandler<Rq, Rs>;
|
|
192
|
+
/**
|
|
193
|
+
* Cria um manipulador de rota para requisições DELETE.
|
|
194
|
+
* @param {string} path O caminho da rota.
|
|
195
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
196
|
+
*/
|
|
197
|
+
delete(path: string): RequestHandler<Rq, Rs>;
|
|
198
|
+
/**
|
|
199
|
+
* Cria um manipulador de rota para requisições PATCH.
|
|
200
|
+
* @param {string} path O caminho da rota.
|
|
201
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
202
|
+
*/
|
|
203
|
+
patch(path: string): RequestHandler<Rq, Rs>;
|
|
204
|
+
/**
|
|
205
|
+
* Cria um manipulador de rota para requisições OPTIONS.
|
|
206
|
+
* @param {string} path O caminho da rota.
|
|
207
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
208
|
+
*/
|
|
209
|
+
options(path: string): RequestHandler<Rq, Rs>;
|
|
210
|
+
/**
|
|
211
|
+
* Cria um manipulador de rota para requisições HEAD.
|
|
212
|
+
* @param {string} path O caminho da rota.
|
|
213
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
214
|
+
*/
|
|
215
|
+
head(path: string): RequestHandler<Rq, Rs>;
|
|
216
|
+
/**
|
|
217
|
+
* Aplica um middleware a um caminho específico. Corresponde a todos os métodos HTTP.
|
|
218
|
+
* @param {string} path O caminho da rota.
|
|
219
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
220
|
+
*/
|
|
221
|
+
all(path: string): RequestHandler<Rq, Rs>;
|
|
222
|
+
/**
|
|
223
|
+
* Aplica um middleware a um caminho específico. Corresponde a todos os métodos HTTP.
|
|
224
|
+
* @param {string} path O caminho da rota.
|
|
225
|
+
* @returns {RequestHandler<Rq, Rs>} Uma instância de `RequestHandler` para encadear middlewares e o manipulador final.
|
|
226
|
+
*/
|
|
227
|
+
use(path: string): RequestHandler<Rq, Rs>;
|
|
228
|
+
/**
|
|
229
|
+
* Obtém uma lista de todas as rotas e middlewares registrados nesta instância do roteador.
|
|
230
|
+
* Útil para introspecção e depuração.
|
|
231
|
+
* @returns {Array<{path: string, methods: string[], type: 'ROUTE' | 'MIDDLEWARE', swagger?: object}>}
|
|
232
|
+
*/
|
|
233
|
+
get routes(): {
|
|
234
|
+
path: string;
|
|
235
|
+
methods: string[];
|
|
236
|
+
type: "ROUTE" | "MIDDLEWARE";
|
|
237
|
+
swagger?: Pick<swaggerJSDoc.OAS3Definition, "paths" | "components">;
|
|
238
|
+
}[];
|
|
239
|
+
/**
|
|
240
|
+
* Agrega toda a documentação de rota (definida via `.doc()`) e de middlewares
|
|
241
|
+
* para gerar uma especificação completa do OpenAPI v3.
|
|
242
|
+
*
|
|
243
|
+
* Este método percorre todas as rotas registradas, coleta suas definições de OpenAPI
|
|
244
|
+
* e as mescla em um único objeto de especificação, que pode ser usado diretamente
|
|
245
|
+
* com ferramentas como `swagger-ui-express`.
|
|
246
|
+
*
|
|
247
|
+
* @param {swaggerJSDoc.OAS3Definition} [options] - Um objeto de definição base do OpenAPI.
|
|
248
|
+
* Use-o para fornecer informações globais como `info`, `servers`, `security`, etc.
|
|
249
|
+
* A documentação gerada (`paths`, `components`) será mesclada a este objeto.
|
|
250
|
+
*
|
|
251
|
+
* @param {swaggerJSDoc.Responses} [defaultResponses={}] - Um objeto contendo respostas padrão
|
|
252
|
+
* (por exemplo, `400`, `401`, `500`) que serão adicionadas a **todas** as rotas.
|
|
253
|
+
* Se uma rota definir uma resposta com o mesmo código de status, a definição da rota
|
|
254
|
+
* terá precedência.
|
|
255
|
+
*
|
|
256
|
+
* @returns {swaggerJSDoc.Options} Um objeto de opções completo, pronto para ser usado
|
|
257
|
+
* pelo `swagger-jsdoc` ou `swagger-ui-express`.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* import express from "express";
|
|
261
|
+
* import swaggerUi from "swagger-ui-express";
|
|
262
|
+
* import { Router } from "./router";
|
|
263
|
+
*
|
|
264
|
+
* const apiRouter = new Router();
|
|
265
|
+
*
|
|
266
|
+
* apiRouter.get("/health")
|
|
267
|
+
* .handler((req, res) => res.send("OK"))
|
|
268
|
+
* .doc({
|
|
269
|
+
* summary: "Verifica a saúde da API",
|
|
270
|
+
* tags: ["Status"],
|
|
271
|
+
* responses: { "200": { description: "API está operacional" } }
|
|
272
|
+
* });
|
|
273
|
+
*
|
|
274
|
+
* // Definições base para o Swagger
|
|
275
|
+
* const swaggerDefinition = {
|
|
276
|
+
* openapi: "3.0.0",
|
|
277
|
+
* info: { title: "Minha API", version: "1.0.0" },
|
|
278
|
+
* servers: [{ url: "http://localhost:3000" }],
|
|
279
|
+
* };
|
|
280
|
+
*
|
|
281
|
+
* // Respostas padrão para todas as rotas
|
|
282
|
+
* const defaultResponses = {
|
|
283
|
+
* "400": { description: "Requisição inválida" },
|
|
284
|
+
* "500": { description: "Erro interno do servidor" },
|
|
285
|
+
* };
|
|
286
|
+
*
|
|
287
|
+
* // Gera as opções do Swagger
|
|
288
|
+
* const swaggerOptions = apiRouter.getSwagger(swaggerDefinition, defaultResponses);
|
|
289
|
+
*
|
|
290
|
+
* // Integra com o Express
|
|
291
|
+
* const app = express();
|
|
292
|
+
* app.use('/api', apiRouter.router);
|
|
293
|
+
* app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerOptions));
|
|
294
|
+
*
|
|
295
|
+
* app.listen(3000);
|
|
296
|
+
*/
|
|
297
|
+
getSwagger(options?: swaggerJSDoc.OAS3Definition, defaultResponses?: swaggerJSDoc.Responses): swaggerJSDoc.Options;
|
|
298
|
+
/**
|
|
299
|
+
* Cria e retorna um novo sub-roteador que é montado em um prefixo de caminho específico.
|
|
300
|
+
*
|
|
301
|
+
* Este método é ideal para organizar rotas relacionadas em módulos. Todas as rotas
|
|
302
|
+
* definidas no roteador retornado serão prefixadas com o `path` fornecido.
|
|
303
|
+
* A nova instância do roteador herda os middlewares do roteador pai.
|
|
304
|
+
*
|
|
305
|
+
* @param {string} path - O prefixo do caminho para o sub-roteador.
|
|
306
|
+
* @returns {Router<Rq, Rs>} Uma nova instância de `Router` para definir rotas dentro do caminho especificado.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* import { Router } from "./router";
|
|
310
|
+
* import express from "express";
|
|
311
|
+
*
|
|
312
|
+
* const app = express();
|
|
313
|
+
* const mainRouter = new Router();
|
|
314
|
+
*
|
|
315
|
+
* // Cria um sub-roteador para a seção de administração.
|
|
316
|
+
* const adminRouter = mainRouter.route("/admin");
|
|
317
|
+
*
|
|
318
|
+
* // Adiciona uma rota ao sub-roteador. O caminho final será "/admin/dashboard".
|
|
319
|
+
* adminRouter.get("/dashboard").handler((req, res) => {
|
|
320
|
+
* res.send("Bem-vindo ao painel de administração!");
|
|
321
|
+
* });
|
|
322
|
+
*
|
|
323
|
+
* // Usa o roteador principal no aplicativo Express.
|
|
324
|
+
* app.use(mainRouter.router);
|
|
325
|
+
*/
|
|
326
|
+
route(path: string): Router<Rq, Rs>;
|
|
327
|
+
/**
|
|
328
|
+
* Monta um sub-roteador no caminho base da instância atual do roteador.
|
|
329
|
+
*
|
|
330
|
+
* Este método permite compor a aplicação anexando um roteador pré-configurado
|
|
331
|
+
* (seja uma instância de `Router` ou `express.Router`) como um middleware.
|
|
332
|
+
* Todas as rotas definidas no roteador fornecido serão acessíveis a partir do
|
|
333
|
+
* ponto de montagem do roteador atual.
|
|
334
|
+
*
|
|
335
|
+
* @param {Router | ExpressRouter} router - A instância do roteador a ser montada.
|
|
336
|
+
* @returns {this} A instância atual do `Router`, permitindo encadeamento de métodos.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* // ---- user.routes.ts ----
|
|
340
|
+
* import { Router } from './router';
|
|
341
|
+
*
|
|
342
|
+
* const userRouter = new Router();
|
|
343
|
+
* userRouter.get('/', (req, res) => res.send('Lista de usuários'));
|
|
344
|
+
* userRouter.get('/:id', (req, res) => res.send(`Detalhes do usuário ${req.params.id}`));
|
|
345
|
+
*
|
|
346
|
+
* export default userRouter;
|
|
347
|
+
*
|
|
348
|
+
* // ---- app.ts ----
|
|
349
|
+
* import express from 'express';
|
|
350
|
+
* import { Router } from './router';
|
|
351
|
+
* import userRouter from './user.routes';
|
|
352
|
+
*
|
|
353
|
+
* const app = express();
|
|
354
|
+
* const apiRouter = new Router();
|
|
355
|
+
*
|
|
356
|
+
* // Monta o userRouter no apiRouter.
|
|
357
|
+
* apiRouter.by(userRouter);
|
|
358
|
+
*
|
|
359
|
+
* // Usa o roteador principal na aplicação sob o prefixo '/api'.
|
|
360
|
+
* // As rotas de userRouter agora são acessíveis em '/api/' e '/api/:id'.
|
|
361
|
+
* app.use('/api', apiRouter.router);
|
|
362
|
+
*/
|
|
363
|
+
by(router: Router | ExpressRouter): this;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Representa as propriedades de uma rota finalizada, permitindo a adição de metadados, como a documentação Swagger.
|
|
367
|
+
* Esta classe é retornada pelo método `.handler()` e seu principal objetivo é fornecer o método `.doc()`
|
|
368
|
+
* para anexar a documentação OpenAPI a um endpoint.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* // ... continuação do exemplo do RouterContext
|
|
372
|
+
* router.get("/users/:id")
|
|
373
|
+
* .handler((req, res) => {
|
|
374
|
+
* res.json({ id: req.params.id, name: "Exemplo" });
|
|
375
|
+
* })
|
|
376
|
+
* // O método .doc() é chamado na instância de RouterProps retornada por .handler()
|
|
377
|
+
* .doc({
|
|
378
|
+
* summary: "Obtém um usuário pelo ID",
|
|
379
|
+
* description: "Retorna os detalhes de um usuário específico.",
|
|
380
|
+
* tags: ["Users"],
|
|
381
|
+
* parameters: [{
|
|
382
|
+
* name: "id",
|
|
383
|
+
* in: "path",
|
|
384
|
+
* required: true,
|
|
385
|
+
* schema: { type: "integer" }
|
|
386
|
+
* }],
|
|
387
|
+
* responses: {
|
|
388
|
+
* "200": {
|
|
389
|
+
* description: "Usuário encontrado."
|
|
390
|
+
* }
|
|
391
|
+
* }
|
|
392
|
+
* });
|
|
393
|
+
*/
|
|
394
|
+
export declare class RouterProps {
|
|
395
|
+
readonly type: RouterMethods;
|
|
396
|
+
readonly middlewares: MiddlewareFC<any, any>[];
|
|
397
|
+
readonly handler: Function;
|
|
398
|
+
readonly hierarchicalMiddleware: MiddlewareFC<any, any>[];
|
|
399
|
+
/**
|
|
400
|
+
* @param {RouterMethods} type O método HTTP da rota.
|
|
401
|
+
* @param {MiddlewareFC<any, any>[]} middlewares A lista de middlewares aplicados à rota.
|
|
402
|
+
* @param {Function} handler A função de handler final da rota.
|
|
403
|
+
*/
|
|
404
|
+
constructor(type: RouterMethods, middlewares: MiddlewareFC<any, any>[] | undefined, handler: Function, hierarchicalMiddleware?: MiddlewareFC<any, any>[]);
|
|
405
|
+
/**
|
|
406
|
+
* Anexa a documentação Swagger/OpenAPI a uma rota.
|
|
407
|
+
* Esta função mescla a documentação fornecida com qualquer documentação
|
|
408
|
+
* definida nos middlewares (`middleware.doc`) que foram aplicados à rota.
|
|
409
|
+
*
|
|
410
|
+
* @param {swaggerJSDoc.Operation} operation O objeto de operação do OpenAPI que descreve o endpoint.
|
|
411
|
+
* @param {swaggerJSDoc.Components} [components={}] Definições de componentes reutilizáveis (schemas, securitySchemes, etc.).
|
|
412
|
+
* @returns {this} Retorna a própria instância de `RouterProps` para permitir encadeamento futuro (se houver).
|
|
413
|
+
*/
|
|
414
|
+
doc(operation: swaggerJSDoc.Operation, components?: swaggerJSDoc.Components): this;
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTests.d.ts","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":"AA8CA,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,SAE1C,CAAC;AAEF,eAAO,MAAM,eAAe,YAE3B,CAAC"}
|