@ismael1361/router 1.2.91 → 2.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 +956 -505
- package/dist/1.0/Doc/index.d.ts.map +1 -0
- package/dist/1.0/Doc/type.d.ts.map +1 -0
- package/dist/1.0/HandleError.d.ts.map +1 -0
- package/dist/1.0/Layer.d.ts.map +1 -0
- package/dist/1.0/Middlewares.d.ts.map +1 -0
- package/dist/1.0/handler.d.ts.map +1 -0
- package/dist/1.0/index.d.ts +150 -0
- package/dist/1.0/index.d.ts.map +1 -0
- package/dist/1.0/middleware.d.ts.map +1 -0
- package/dist/1.0/redocUi/index.d.ts.map +1 -0
- package/dist/1.0/router.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/index.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/lib/anchor.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/lib/inArray.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/models/schema.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/contact.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/dataTypes.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/definitions.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/externalDocs.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/info.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/license.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/path.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/pathParameters.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/pathResponses.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/security.d.ts.map +1 -0
- package/dist/1.0/swagger-markdown/transformers/securityDefinitions.d.ts.map +1 -0
- package/dist/{type.d.ts → 1.0/type.d.ts} +1 -1
- package/dist/1.0/type.d.ts.map +1 -0
- package/dist/1.0/utils.d.ts.map +1 -0
- package/dist/2.0/HandleError.d.ts +127 -0
- package/dist/2.0/HandleError.d.ts.map +1 -0
- package/dist/2.0/HandleError.esm.js.map +1 -0
- package/dist/2.0/HandleError.js.map +1 -0
- package/dist/2.0/Middlewares.d.ts +178 -0
- package/dist/2.0/Middlewares.d.ts.map +1 -0
- package/dist/{Middlewares.esm.js → 2.0/Middlewares.esm.js} +5 -5
- package/dist/2.0/Middlewares.esm.js.map +1 -0
- package/dist/{Middlewares.js → 2.0/Middlewares.js} +5 -5
- package/dist/2.0/Middlewares.js.map +1 -0
- package/dist/2.0/analyzeSwagger.d.ts +7 -0
- package/dist/2.0/analyzeSwagger.d.ts.map +1 -0
- package/dist/2.0/analyzeSwagger.esm.js +432 -0
- package/dist/2.0/analyzeSwagger.esm.js.map +1 -0
- package/dist/2.0/analyzeSwagger.js +435 -0
- package/dist/2.0/analyzeSwagger.js.map +1 -0
- package/dist/2.0/create.d.ts +75 -0
- package/dist/2.0/create.d.ts.map +1 -0
- package/dist/2.0/create.esm.js +321 -0
- package/dist/2.0/create.esm.js.map +1 -0
- package/dist/2.0/create.js +323 -0
- package/dist/2.0/create.js.map +1 -0
- package/dist/2.0/handler.d.ts +149 -0
- package/dist/2.0/handler.d.ts.map +1 -0
- package/dist/2.0/handler.esm.js +188 -0
- package/dist/2.0/handler.esm.js.map +1 -0
- package/dist/2.0/handler.js +191 -0
- package/dist/2.0/handler.js.map +1 -0
- package/dist/2.0/index.d.ts +7 -0
- package/dist/2.0/index.d.ts.map +1 -0
- package/dist/2.0/redocUi/index.d.ts +4 -0
- package/dist/2.0/redocUi/index.d.ts.map +1 -0
- package/dist/{redocUi → 2.0/redocUi}/index.esm.js +1 -1
- package/dist/2.0/redocUi/index.esm.js.map +1 -0
- package/dist/{redocUi → 2.0/redocUi}/index.js +1 -1
- package/dist/2.0/redocUi/index.js.map +1 -0
- package/dist/2.0/renderChainDocs.d.ts +3 -0
- package/dist/2.0/renderChainDocs.d.ts.map +1 -0
- package/dist/2.0/renderChainDocs.esm.js +118 -0
- package/dist/2.0/renderChainDocs.esm.js.map +1 -0
- package/dist/2.0/renderChainDocs.js +120 -0
- package/dist/2.0/renderChainDocs.js.map +1 -0
- package/dist/2.0/router.d.ts +73 -0
- package/dist/2.0/router.d.ts.map +1 -0
- package/dist/2.0/router.esm.js +302 -0
- package/dist/2.0/router.esm.js.map +1 -0
- package/dist/2.0/router.js +304 -0
- package/dist/2.0/router.js.map +1 -0
- package/dist/2.0/swagger-markdown/index.d.ts +10 -0
- package/dist/2.0/swagger-markdown/index.d.ts.map +1 -0
- package/dist/{swagger-markdown → 2.0/swagger-markdown}/index.esm.js +1 -1
- package/dist/2.0/swagger-markdown/index.esm.js.map +1 -0
- package/dist/{swagger-markdown → 2.0/swagger-markdown}/index.js +1 -1
- package/dist/2.0/swagger-markdown/index.js.map +1 -0
- package/dist/2.0/swagger-markdown/lib/anchor.d.ts +6 -0
- package/dist/2.0/swagger-markdown/lib/anchor.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/lib/anchor.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/lib/anchor.js.map +1 -0
- package/dist/2.0/swagger-markdown/lib/inArray.d.ts +9 -0
- package/dist/2.0/swagger-markdown/lib/inArray.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/lib/inArray.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/lib/inArray.js.map +1 -0
- package/dist/2.0/swagger-markdown/models/schema.d.ts +28 -0
- package/dist/2.0/swagger-markdown/models/schema.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/models/schema.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/models/schema.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/contact.d.ts +8 -0
- package/dist/2.0/swagger-markdown/transformers/contact.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/contact.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/contact.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/dataTypes.d.ts +9 -0
- package/dist/2.0/swagger-markdown/transformers/dataTypes.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/dataTypes.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/dataTypes.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/definitions.d.ts +14 -0
- package/dist/2.0/swagger-markdown/transformers/definitions.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/definitions.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/definitions.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/externalDocs.d.ts +4 -0
- package/dist/2.0/swagger-markdown/transformers/externalDocs.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/externalDocs.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/externalDocs.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/info.d.ts +11 -0
- package/dist/2.0/swagger-markdown/transformers/info.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/info.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/info.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/license.d.ts +8 -0
- package/dist/2.0/swagger-markdown/transformers/license.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/license.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/license.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/path.d.ts +9 -0
- package/dist/2.0/swagger-markdown/transformers/path.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/path.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/path.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathParameters.d.ts +4 -0
- package/dist/2.0/swagger-markdown/transformers/pathParameters.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathParameters.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathParameters.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathResponses.d.ts +9 -0
- package/dist/2.0/swagger-markdown/transformers/pathResponses.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathResponses.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/pathResponses.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/security.d.ts +4 -0
- package/dist/2.0/swagger-markdown/transformers/security.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/security.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/security.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/securityDefinitions.d.ts +6 -0
- package/dist/2.0/swagger-markdown/transformers/securityDefinitions.d.ts.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/securityDefinitions.esm.js.map +1 -0
- package/dist/2.0/swagger-markdown/transformers/securityDefinitions.js.map +1 -0
- package/dist/2.0/type.d.ts +654 -0
- package/dist/2.0/type.d.ts.map +1 -0
- package/dist/2.0/utils.d.ts +79 -0
- package/dist/2.0/utils.d.ts.map +1 -0
- package/dist/{utils.esm.js → 2.0/utils.esm.js} +61 -89
- package/dist/2.0/utils.esm.js.map +1 -0
- package/dist/{utils.js → 2.0/utils.js} +65 -94
- package/dist/2.0/utils.js.map +1 -0
- package/dist/index.d.ts +1 -149
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +5 -163
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +9 -169
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/dist/Doc/index.d.ts.map +0 -1
- package/dist/Doc/type.d.ts.map +0 -1
- package/dist/HandleError.d.ts.map +0 -1
- package/dist/HandleError.esm.js.map +0 -1
- package/dist/HandleError.js.map +0 -1
- package/dist/Layer.d.ts.map +0 -1
- package/dist/Layer.esm.js +0 -274
- package/dist/Layer.esm.js.map +0 -1
- package/dist/Layer.js +0 -276
- package/dist/Layer.js.map +0 -1
- package/dist/Middlewares.d.ts.map +0 -1
- package/dist/Middlewares.esm.js.map +0 -1
- package/dist/Middlewares.js.map +0 -1
- package/dist/handler.d.ts.map +0 -1
- package/dist/handler.esm.js +0 -171
- package/dist/handler.esm.js.map +0 -1
- package/dist/handler.js +0 -174
- package/dist/handler.js.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.esm.js +0 -152
- package/dist/middleware.esm.js.map +0 -1
- package/dist/middleware.js +0 -155
- package/dist/middleware.js.map +0 -1
- package/dist/redocUi/index.d.ts.map +0 -1
- package/dist/redocUi/index.esm.js.map +0 -1
- package/dist/redocUi/index.js.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/router.esm.js +0 -719
- package/dist/router.esm.js.map +0 -1
- package/dist/router.js +0 -740
- package/dist/router.js.map +0 -1
- package/dist/swagger-markdown/index.d.ts.map +0 -1
- package/dist/swagger-markdown/index.esm.js.map +0 -1
- package/dist/swagger-markdown/index.js.map +0 -1
- package/dist/swagger-markdown/lib/anchor.d.ts.map +0 -1
- package/dist/swagger-markdown/lib/anchor.esm.js.map +0 -1
- package/dist/swagger-markdown/lib/anchor.js.map +0 -1
- package/dist/swagger-markdown/lib/inArray.d.ts.map +0 -1
- package/dist/swagger-markdown/lib/inArray.esm.js.map +0 -1
- package/dist/swagger-markdown/lib/inArray.js.map +0 -1
- package/dist/swagger-markdown/models/schema.d.ts.map +0 -1
- package/dist/swagger-markdown/models/schema.esm.js.map +0 -1
- package/dist/swagger-markdown/models/schema.js.map +0 -1
- package/dist/swagger-markdown/transformers/contact.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/contact.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/contact.js.map +0 -1
- package/dist/swagger-markdown/transformers/dataTypes.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/dataTypes.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/dataTypes.js.map +0 -1
- package/dist/swagger-markdown/transformers/definitions.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/definitions.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/definitions.js.map +0 -1
- package/dist/swagger-markdown/transformers/externalDocs.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/externalDocs.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/externalDocs.js.map +0 -1
- package/dist/swagger-markdown/transformers/info.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/info.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/info.js.map +0 -1
- package/dist/swagger-markdown/transformers/license.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/license.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/license.js.map +0 -1
- package/dist/swagger-markdown/transformers/path.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/path.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/path.js.map +0 -1
- package/dist/swagger-markdown/transformers/pathParameters.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/pathParameters.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/pathParameters.js.map +0 -1
- package/dist/swagger-markdown/transformers/pathResponses.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/pathResponses.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/pathResponses.js.map +0 -1
- package/dist/swagger-markdown/transformers/security.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/security.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/security.js.map +0 -1
- package/dist/swagger-markdown/transformers/securityDefinitions.d.ts.map +0 -1
- package/dist/swagger-markdown/transformers/securityDefinitions.esm.js.map +0 -1
- package/dist/swagger-markdown/transformers/securityDefinitions.js.map +0 -1
- package/dist/type.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.esm.js.map +0 -1
- package/dist/utils.js.map +0 -1
- /package/dist/{Doc → 1.0/Doc}/index.d.ts +0 -0
- /package/dist/{Doc → 1.0/Doc}/type.d.ts +0 -0
- /package/dist/{HandleError.d.ts → 1.0/HandleError.d.ts} +0 -0
- /package/dist/{Layer.d.ts → 1.0/Layer.d.ts} +0 -0
- /package/dist/{Middlewares.d.ts → 1.0/Middlewares.d.ts} +0 -0
- /package/dist/{handler.d.ts → 1.0/handler.d.ts} +0 -0
- /package/dist/{middleware.d.ts → 1.0/middleware.d.ts} +0 -0
- /package/dist/{redocUi → 1.0/redocUi}/index.d.ts +0 -0
- /package/dist/{router.d.ts → 1.0/router.d.ts} +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/index.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/lib/anchor.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/lib/inArray.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/models/schema.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/contact.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/dataTypes.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/definitions.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/externalDocs.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/info.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/license.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/path.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/pathParameters.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/pathResponses.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/security.d.ts +0 -0
- /package/dist/{swagger-markdown → 1.0/swagger-markdown}/transformers/securityDefinitions.d.ts +0 -0
- /package/dist/{utils.d.ts → 1.0/utils.d.ts} +0 -0
- /package/dist/{HandleError.esm.js → 2.0/HandleError.esm.js} +0 -0
- /package/dist/{HandleError.js → 2.0/HandleError.js} +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/anchor.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/anchor.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/inArray.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/lib/inArray.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/models/schema.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/models/schema.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/contact.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/contact.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/dataTypes.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/dataTypes.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/definitions.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/definitions.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/externalDocs.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/externalDocs.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/info.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/info.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/license.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/license.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/path.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/path.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathParameters.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathParameters.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathResponses.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/pathResponses.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/security.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/security.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/securityDefinitions.esm.js +0 -0
- /package/dist/{swagger-markdown → 2.0/swagger-markdown}/transformers/securityDefinitions.js +0 -0
package/README.md
CHANGED
|
@@ -4,33 +4,49 @@
|
|
|
4
4
|
[](https://github.com/ismael1361/router/blob/main/MIT)
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Módulo para Express.js com tipagem encadeada forte para `body`, `params`, `query` e propriedades customizadas de `Request`/`Response`. Gera automaticamente documentação OpenAPI 3.0 (Swagger UI, ReDoc e Markdown), code snippets multi-linguagem e oferece sistema de logging por stacks integrado.
|
|
8
8
|
|
|
9
9
|
## 📋 Índice
|
|
10
10
|
|
|
11
11
|
- [Características](#-características)
|
|
12
12
|
- [Instalação](#-instalação)
|
|
13
13
|
- [Início Rápido](#-início-rápido)
|
|
14
|
-
- [API
|
|
15
|
-
- [create](#create)
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
14
|
+
- [API](#-api)
|
|
15
|
+
- [`create()`](#create)
|
|
16
|
+
- [`router()`](#router)
|
|
17
|
+
- [`handler()`](#handler)
|
|
18
|
+
- [`middleware()`](#middleware)
|
|
19
|
+
- [`HandleError`](#handleerror)
|
|
20
|
+
- [`Middlewares`](#middlewares)
|
|
21
|
+
- [Interfaces e Tipos](#-interfaces-e-tipos)
|
|
22
|
+
- [`IApplication`](#iapplication)
|
|
23
|
+
- [`IRouter`](#irouter)
|
|
24
|
+
- [`IHandler`](#ihandler)
|
|
25
|
+
- [`IMiddleware`](#imiddleware)
|
|
26
|
+
- [`Request`](#request)
|
|
27
|
+
- [`Response`](#response)
|
|
28
|
+
- [`SwaggerOptions`](#swaggeroptions)
|
|
29
|
+
- [Métodos HTTP](#-métodos-http)
|
|
30
|
+
- [Rotas e Sub-routers](#-rotas-e-sub-routers)
|
|
20
31
|
- [Documentação OpenAPI/Swagger](#-documentação-openapiswagger)
|
|
21
|
-
- [
|
|
32
|
+
- [Sistema de Stacks (Logging)](#-sistema-de-stacks-logging)
|
|
33
|
+
- [Exemplos Avançados](#-exemplos-avançados)
|
|
22
34
|
- [Contribuindo](#-contribuindo)
|
|
23
35
|
- [Licença](#-licença)
|
|
24
36
|
|
|
25
37
|
## ✨ Características
|
|
26
38
|
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
39
|
+
- **Tipagem Forte Encadeada** — tipos de `Request` e `Response` acumulados automaticamente a cada `.handler()` encadeado via `JoinRequest`/`JoinResponse`
|
|
40
|
+
- **Inferência de Parâmetros de Rota** — `req.params` tipado diretamente a partir da string de rota (ex.: `"/users/:id"` → `req.params.id: string`)
|
|
41
|
+
- **Documentação OpenAPI 3.0 Automática** — geração de spec, Swagger UI, ReDoc e Markdown a partir de `.doc()` em handlers, middlewares e rotas
|
|
42
|
+
- **Code Snippets** — geração automática de exemplos de código em 20+ linguagens (cURL, Python, Node.js, C#, Go, etc.)
|
|
43
|
+
- **Middlewares Tipados com `.doc()`** — middlewares criados via `middleware()` carregam documentação OpenAPI que é mesclada automaticamente na spec
|
|
44
|
+
- **Sub-routers Modulares** — `router()` e `.route()` permitem compor APIs em módulos independentes com prefixos
|
|
45
|
+
- **Tratamento de Erros Centralizado** — `HandleError` com código HTTP, nível de log e integração automática com o sistema de stacks
|
|
46
|
+
- **Sistema de Stacks** — logging automatizado de erros, warnings e informações em arquivo, com UI HTML acessível por rota
|
|
47
|
+
- **CORS Configurável** — middleware `Middlewares.cors()` com controle granular de origens, métodos, headers e credenciais
|
|
48
|
+
- **Upload de Arquivos** — middleware `Middlewares.files()` com parsing de `multipart/form-data` e filtragem por MIME type
|
|
49
|
+
- **Execução Única de Middleware** — `req.executeOnce()` impede re-execução de middlewares em rotas aninhadas
|
|
34
50
|
|
|
35
51
|
## 📦 Instalação
|
|
36
52
|
|
|
@@ -38,8 +54,6 @@ Um módulo moderno e robusto para criar e gerenciar rotas em Express.js com tipa
|
|
|
38
54
|
npm install @ismael1361/router
|
|
39
55
|
```
|
|
40
56
|
|
|
41
|
-
ou
|
|
42
|
-
|
|
43
57
|
```bash
|
|
44
58
|
yarn add @ismael1361/router
|
|
45
59
|
```
|
|
@@ -47,680 +61,1123 @@ yarn add @ismael1361/router
|
|
|
47
61
|
## 🚀 Início Rápido
|
|
48
62
|
|
|
49
63
|
```typescript
|
|
50
|
-
import { create, Middlewares } from
|
|
64
|
+
import { create, router, middleware, Middlewares, Request } from "@ismael1361/router";
|
|
51
65
|
|
|
52
66
|
const app = create();
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const router = app.route();
|
|
68
|
+
// Middlewares globais
|
|
69
|
+
app.use(Middlewares.json());
|
|
70
|
+
app.use(Middlewares.cors({ allowOrigin: "*" }));
|
|
58
71
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
.
|
|
62
|
-
|
|
63
|
-
res.json({
|
|
64
|
-
id: req.params.id,
|
|
65
|
-
name: 'John Doe'
|
|
66
|
-
});
|
|
72
|
+
// Rota simples com inferência de parâmetros
|
|
73
|
+
app.get("/users/:id")
|
|
74
|
+
.handler((req, res) => {
|
|
75
|
+
// req.params.id é automaticamente inferido como string
|
|
76
|
+
res.json({ id: req.params.id, name: "John Doe" });
|
|
67
77
|
})
|
|
68
78
|
.doc({
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
description: 'ID do usuário',
|
|
75
|
-
type: 'string',
|
|
76
|
-
required: true
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
+
tags: ["Users"],
|
|
80
|
+
summary: "Obter usuário por ID",
|
|
81
|
+
parameters: [
|
|
82
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } },
|
|
83
|
+
],
|
|
79
84
|
responses: {
|
|
80
|
-
200: { description:
|
|
81
|
-
404: { description:
|
|
82
|
-
}
|
|
85
|
+
200: { description: "Usuário encontrado" },
|
|
86
|
+
404: { description: "Usuário não encontrado" },
|
|
87
|
+
},
|
|
83
88
|
});
|
|
84
89
|
|
|
90
|
+
// Documentação Swagger
|
|
91
|
+
app.defineSwagger({
|
|
92
|
+
openapi: "3.0.0",
|
|
93
|
+
info: { title: "Minha API", version: "1.0.0" },
|
|
94
|
+
});
|
|
95
|
+
|
|
85
96
|
app.listen(3000, () => {
|
|
86
|
-
console.log(
|
|
97
|
+
console.log("Servidor: http://localhost:3000");
|
|
98
|
+
console.log("Swagger: http://localhost:3000/doc/swagger");
|
|
99
|
+
console.log("ReDoc: http://localhost:3000/doc/redoc");
|
|
87
100
|
});
|
|
88
101
|
```
|
|
89
102
|
|
|
90
|
-
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 📖 API
|
|
91
106
|
|
|
92
|
-
### create
|
|
107
|
+
### `create()`
|
|
93
108
|
|
|
94
|
-
Cria uma
|
|
109
|
+
Cria uma instância de `IApplication`, que encapsula uma aplicação Express com roteamento tipado, documentação OpenAPI e sistema de stacks.
|
|
95
110
|
|
|
96
111
|
```typescript
|
|
97
|
-
create
|
|
112
|
+
function create(): IApplication;
|
|
98
113
|
```
|
|
99
114
|
|
|
100
|
-
**Retorno:**
|
|
101
|
-
|
|
102
|
-
**Exemplo:**
|
|
115
|
+
**Retorno:** `IApplication` — herda todos os métodos de `IRouter` (`.get()`, `.post()`, `.route()`, `.use()`, `.defineSwagger()`) e métodos do Express (`listen`, `enable`, `disable`, etc.).
|
|
103
116
|
|
|
104
117
|
```typescript
|
|
105
|
-
import { create
|
|
118
|
+
import { create } from "@ismael1361/router";
|
|
106
119
|
|
|
107
|
-
|
|
108
|
-
user?: { id: string; name: string };
|
|
109
|
-
}
|
|
120
|
+
const app = create();
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
.
|
|
122
|
+
app.get("/hello/:name")
|
|
123
|
+
.handler((req, res) => {
|
|
124
|
+
res.send(`Hello, ${req.params.name}!`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
app.listen(3000, () => {
|
|
128
|
+
console.log("Server is running on http://localhost:3000");
|
|
129
|
+
});
|
|
113
130
|
```
|
|
114
131
|
|
|
115
|
-
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### `router()`
|
|
116
135
|
|
|
117
|
-
Cria
|
|
136
|
+
Cria uma instância independente de `IRouter` para modularizar a API. Pode ser montado em outro router ou aplicação via `.route()` ou `.use()`.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
function router(): IRouter;
|
|
140
|
+
```
|
|
118
141
|
|
|
119
142
|
```typescript
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
143
|
+
import { create, router } from "@ismael1361/router";
|
|
144
|
+
|
|
145
|
+
const app = create();
|
|
146
|
+
|
|
147
|
+
const usersRouter = router();
|
|
148
|
+
|
|
149
|
+
usersRouter.get("/")
|
|
150
|
+
.handler((req, res) => {
|
|
151
|
+
res.json([{ id: "1", name: "Alice" }]);
|
|
152
|
+
})
|
|
153
|
+
.doc({ tags: ["Users"], summary: "Listar usuários" });
|
|
154
|
+
|
|
155
|
+
usersRouter.post("/")
|
|
156
|
+
.handler((req, res) => {
|
|
157
|
+
res.status(201).json({ id: "2", ...req.body });
|
|
158
|
+
})
|
|
159
|
+
.doc({ tags: ["Users"], summary: "Criar usuário" });
|
|
160
|
+
|
|
161
|
+
// Montar com prefixo
|
|
162
|
+
app.route("/users", usersRouter);
|
|
124
163
|
```
|
|
125
164
|
|
|
126
|
-
|
|
127
|
-
- `callback`: Função de middleware padrão do Express `(req, res, next)`
|
|
128
|
-
- `doc` (opcional): Objeto com metadados para documentação OpenAPI
|
|
165
|
+
---
|
|
129
166
|
|
|
130
|
-
|
|
167
|
+
### `handler()`
|
|
131
168
|
|
|
132
|
-
|
|
169
|
+
Cria um handler encadeável que combina execução de middlewares com documentação OpenAPI. Cada chamada a `.handler()` adiciona um middleware à cadeia e mescla os tipos de `Request` e `Response` via `JoinRequest`/`JoinResponse`.
|
|
133
170
|
|
|
134
171
|
```typescript
|
|
135
|
-
|
|
172
|
+
function handler<Rq extends Request, Rs extends Response>(
|
|
173
|
+
fn: RequestHandler<Rq, Rs>
|
|
174
|
+
): IHandler<Rq, Rs>;
|
|
175
|
+
```
|
|
136
176
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
api_key?: string;
|
|
141
|
-
token?: string
|
|
142
|
-
}
|
|
143
|
-
> {
|
|
144
|
-
user: { id: string; roles: string[] };
|
|
145
|
-
}
|
|
177
|
+
```typescript
|
|
178
|
+
import { handler } from "@ismael1361/router";
|
|
146
179
|
|
|
147
|
-
const
|
|
148
|
-
(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
security: [{ bearerAuth: [] }],
|
|
160
|
-
responses: {
|
|
161
|
-
401: {
|
|
162
|
-
description: 'Token de autenticação inválido ou não fornecido'
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
// Usar o middleware
|
|
169
|
-
router
|
|
170
|
-
.get('/profile')
|
|
171
|
-
.middleware(isAuthenticated)
|
|
172
|
-
.handle((req, res) => {
|
|
173
|
-
res.json({ user: req.user });
|
|
180
|
+
const myHandler = handler((req, res, next) => {
|
|
181
|
+
console.log("Primeiro middleware");
|
|
182
|
+
next();
|
|
183
|
+
})
|
|
184
|
+
.handler((req, res) => {
|
|
185
|
+
res.json({ status: "ok" });
|
|
186
|
+
})
|
|
187
|
+
.doc({
|
|
188
|
+
tags: ["Health"],
|
|
189
|
+
summary: "Health check",
|
|
174
190
|
});
|
|
175
191
|
```
|
|
176
192
|
|
|
177
|
-
|
|
193
|
+
> Na maioria dos casos, `handler()` é usado internamente pelo router ao registrar rotas (`.get()`, `.post()`, etc.). O uso direto é raro.
|
|
194
|
+
|
|
195
|
+
---
|
|
178
196
|
|
|
179
|
-
|
|
197
|
+
### `middleware()`
|
|
198
|
+
|
|
199
|
+
Cria um middleware reutilizável com suporte a documentação OpenAPI. Os tipos genéricos do middleware são mesclados automaticamente quando encadeado via `.handler()`.
|
|
180
200
|
|
|
181
201
|
```typescript
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
):
|
|
202
|
+
function middleware<Req extends Request, Res extends Response>(
|
|
203
|
+
fn: RequestHandler<Req, Res>
|
|
204
|
+
): IMiddleware<Req, Res>;
|
|
185
205
|
```
|
|
186
206
|
|
|
187
|
-
**
|
|
188
|
-
- `path`: Caminho da URL para a rota
|
|
189
|
-
|
|
190
|
-
**Retorno:** Nova instância do Router "travada" no path especificado
|
|
207
|
+
O middleware retornado **não** possui o método `.handler()` — apenas `.doc()`. Ele deve ser encadeado via `.handler()` de um `IHandler`.
|
|
191
208
|
|
|
192
|
-
|
|
209
|
+
#### Middleware simples
|
|
193
210
|
|
|
194
211
|
```typescript
|
|
195
|
-
import {
|
|
212
|
+
import { middleware } from "@ismael1361/router";
|
|
196
213
|
|
|
197
|
-
const
|
|
214
|
+
const logMiddleware = middleware((req, res, next) => {
|
|
215
|
+
console.log(`${req.method} ${req.url}`);
|
|
216
|
+
next();
|
|
217
|
+
});
|
|
198
218
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
.
|
|
202
|
-
|
|
203
|
-
res.json([{ id: 1, title: 'Aprender @ismael1361/router' }]);
|
|
204
|
-
})
|
|
205
|
-
.doc({
|
|
206
|
-
summary: 'Listar todas as tarefas',
|
|
207
|
-
tags: ['Tasks'],
|
|
208
|
-
responses: { 200: { description: 'Lista de tarefas' } }
|
|
219
|
+
app.get("/users")
|
|
220
|
+
.handler(logMiddleware)
|
|
221
|
+
.handler((req, res) => {
|
|
222
|
+
res.json([]);
|
|
209
223
|
});
|
|
224
|
+
```
|
|
210
225
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
#### Middleware com tipo customizado e documentação
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { middleware, Request } from "@ismael1361/router";
|
|
230
|
+
|
|
231
|
+
interface AuthRequest extends Request {
|
|
232
|
+
user: { userId: string; roles: string[] };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const authMiddleware = middleware((req: AuthRequest, res, next) => {
|
|
236
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
237
|
+
if (!token) {
|
|
238
|
+
res.status(401).json({ error: "Token ausente" });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
req.user = { userId: "123", roles: ["admin"] };
|
|
242
|
+
next();
|
|
243
|
+
}).doc({
|
|
244
|
+
security: [{ bearerAuth: [] }],
|
|
245
|
+
components: {
|
|
246
|
+
securitySchemes: {
|
|
247
|
+
bearerAuth: { type: "http", scheme: "bearer" },
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Ao encadear, req.user é inferido automaticamente
|
|
253
|
+
app.get("/profile")
|
|
254
|
+
.handler(authMiddleware)
|
|
255
|
+
.handler((req, res) => {
|
|
256
|
+
// req.user.userId está disponível com tipagem
|
|
257
|
+
res.json({ userId: req.user.userId });
|
|
223
258
|
});
|
|
259
|
+
```
|
|
224
260
|
|
|
225
|
-
|
|
226
|
-
|
|
261
|
+
#### Middleware de validação de body
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
interface BodyRequest extends Request<string, { name: string; email: string }> {}
|
|
265
|
+
|
|
266
|
+
const validateBody = middleware((req: BodyRequest, res, next) => {
|
|
267
|
+
if (!req.body.name || !req.body.email) {
|
|
268
|
+
res.status(400).json({ error: "name e email são obrigatórios" });
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
next();
|
|
272
|
+
}).doc({
|
|
273
|
+
requestBody: {
|
|
274
|
+
required: true,
|
|
275
|
+
content: {
|
|
276
|
+
"application/json": {
|
|
277
|
+
schema: {
|
|
278
|
+
type: "object",
|
|
279
|
+
required: ["name", "email"],
|
|
280
|
+
properties: {
|
|
281
|
+
name: { type: "string" },
|
|
282
|
+
email: { type: "string", format: "email" },
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
app.post("/users")
|
|
291
|
+
.handler(validateBody)
|
|
292
|
+
.handler((req, res) => {
|
|
293
|
+
// req.body.name e req.body.email inferidos como string
|
|
294
|
+
res.status(201).json({ name: req.body.name, email: req.body.email });
|
|
295
|
+
});
|
|
227
296
|
```
|
|
228
297
|
|
|
229
|
-
|
|
298
|
+
---
|
|
230
299
|
|
|
231
|
-
|
|
300
|
+
### `HandleError`
|
|
232
301
|
|
|
233
|
-
|
|
302
|
+
Classe de erro para tratamento padronizado de erros HTTP. Integra-se automaticamente com o sistema de stacks e o tratamento centralizado de erros do router.
|
|
234
303
|
|
|
235
|
-
##### `.app`
|
|
236
304
|
```typescript
|
|
237
|
-
|
|
305
|
+
class HandleError extends Error {
|
|
306
|
+
constructor(
|
|
307
|
+
message: string,
|
|
308
|
+
name?: string, // default: "DEFAULT"
|
|
309
|
+
cause?: number | Error | string, // código HTTP ou causa
|
|
310
|
+
level?: "ERROR" | "WARN" | "INFO" | "NONE", // default: "ERROR"
|
|
311
|
+
source?: string,
|
|
312
|
+
duration?: number,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
get code(): number; // código HTTP extraído de cause
|
|
316
|
+
get status(): { code: number; message: string };
|
|
317
|
+
get meta(): any;
|
|
318
|
+
}
|
|
238
319
|
```
|
|
239
|
-
Instância do Express subjacente.
|
|
240
320
|
|
|
241
|
-
##### `.routes`
|
|
242
321
|
```typescript
|
|
243
|
-
|
|
244
|
-
path: string;
|
|
245
|
-
methods: string[];
|
|
246
|
-
type: "ROUTE" | "MIDDLEWARE";
|
|
247
|
-
swagger?: Pick<swaggerJSDoc.OAS3Definition, "paths" | "components">;
|
|
248
|
-
}>
|
|
249
|
-
```
|
|
250
|
-
Array de rotas e middlewares registrados para geração de documentação.
|
|
322
|
+
import { HandleError } from "@ismael1361/router";
|
|
251
323
|
|
|
252
|
-
|
|
324
|
+
// Erro 404
|
|
325
|
+
throw new HandleError("Recurso não encontrado", "NOT_FOUND", 404);
|
|
253
326
|
|
|
254
|
-
|
|
255
|
-
|
|
327
|
+
// Erro de validação (nível WARN, não polui logs de erro)
|
|
328
|
+
throw new HandleError("Campo email inválido", "VALIDATION_ERROR", 400, "WARN");
|
|
256
329
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
tags: ['Health'],
|
|
266
|
-
responses: { 200: { description: 'API funcionando' } }
|
|
330
|
+
// Uso em handler
|
|
331
|
+
app.get("/users/:id")
|
|
332
|
+
.handler((req, res) => {
|
|
333
|
+
const user = findUser(req.params.id);
|
|
334
|
+
if (!user) {
|
|
335
|
+
throw new HandleError("Usuário não encontrado", "NOT_FOUND", 404);
|
|
336
|
+
}
|
|
337
|
+
res.json(user);
|
|
267
338
|
});
|
|
268
339
|
```
|
|
269
340
|
|
|
270
|
-
|
|
271
|
-
Registra uma rota POST.
|
|
341
|
+
O erro é capturado automaticamente pelo sistema interno (`tryHandler`) e retorna resposta JSON padronizada:
|
|
272
342
|
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
.post('/users')
|
|
276
|
-
.handle((req, res) => {
|
|
277
|
-
const newUser = req.body;
|
|
278
|
-
res.status(201).json({ id: Date.now(), ...newUser });
|
|
279
|
-
})
|
|
280
|
-
.doc({
|
|
281
|
-
summary: 'Criar novo usuário',
|
|
282
|
-
tags: ['Users'],
|
|
283
|
-
body: {
|
|
284
|
-
description: 'Dados do usuário',
|
|
285
|
-
schema: {
|
|
286
|
-
type: 'object',
|
|
287
|
-
properties: {
|
|
288
|
-
name: { type: 'string' },
|
|
289
|
-
email: { type: 'string' }
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
responses: { 201: { description: 'Usuário criado' } }
|
|
294
|
-
});
|
|
343
|
+
```json
|
|
344
|
+
{ "message": "Usuário não encontrado", "name": "NOT_FOUND", "code": 404 }
|
|
295
345
|
```
|
|
296
346
|
|
|
297
|
-
|
|
298
|
-
Registra uma rota PUT para substituição completa de recursos.
|
|
347
|
+
---
|
|
299
348
|
|
|
300
|
-
|
|
301
|
-
Registra uma rota PATCH para atualizações parciais.
|
|
349
|
+
### `Middlewares`
|
|
302
350
|
|
|
303
|
-
|
|
304
|
-
Registra uma rota DELETE para remoção de recursos.
|
|
351
|
+
Namespace com middlewares prontos para uso, importável via `Middlewares`.
|
|
305
352
|
|
|
306
|
-
|
|
307
|
-
|
|
353
|
+
```typescript
|
|
354
|
+
import { Middlewares } from "@ismael1361/router";
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### `Middlewares.json(options?)`
|
|
308
358
|
|
|
309
|
-
|
|
310
|
-
Registra uma rota HEAD para obter metadados sem corpo de resposta.
|
|
359
|
+
Analisa corpos de requisição JSON. Wrapper de `body-parser.json()`.
|
|
311
360
|
|
|
312
|
-
|
|
313
|
-
|
|
361
|
+
```typescript
|
|
362
|
+
app.use(Middlewares.json());
|
|
363
|
+
app.use(Middlewares.json({ limit: "10mb" }));
|
|
364
|
+
```
|
|
314
365
|
|
|
315
|
-
####
|
|
366
|
+
#### `Middlewares.raw(options?)`
|
|
316
367
|
|
|
317
|
-
|
|
318
|
-
Monta middlewares em um caminho específico.
|
|
368
|
+
Analisa corpos de requisição como `Buffer`.
|
|
319
369
|
|
|
320
370
|
```typescript
|
|
321
|
-
|
|
322
|
-
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
|
|
323
|
-
next();
|
|
324
|
-
});
|
|
371
|
+
app.use(Middlewares.raw({ type: "application/octet-stream", limit: "10mb" }));
|
|
325
372
|
```
|
|
326
373
|
|
|
327
|
-
|
|
328
|
-
|
|
374
|
+
#### `Middlewares.text(options?)`
|
|
375
|
+
|
|
376
|
+
Analisa corpos de requisição como texto.
|
|
329
377
|
|
|
330
378
|
```typescript
|
|
331
|
-
|
|
379
|
+
app.use(Middlewares.text({ type: "text/plain" }));
|
|
380
|
+
```
|
|
332
381
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
382
|
+
#### `Middlewares.urlencoded(options?)`
|
|
383
|
+
|
|
384
|
+
Analisa dados de formulário `application/x-www-form-urlencoded`.
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
app.use(Middlewares.urlencoded({ extended: true }));
|
|
338
388
|
```
|
|
339
389
|
|
|
340
|
-
|
|
341
|
-
|
|
390
|
+
#### `Middlewares.cors(options?)`
|
|
391
|
+
|
|
392
|
+
Configura CORS com controle granular.
|
|
342
393
|
|
|
343
394
|
```typescript
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
395
|
+
// Permitir todas as origens
|
|
396
|
+
app.use(Middlewares.cors({ allowOrigin: "*" }));
|
|
397
|
+
|
|
398
|
+
// Origem específica com opções
|
|
399
|
+
app.use(Middlewares.cors({
|
|
400
|
+
allowOrigin: "https://meusite.com",
|
|
401
|
+
allowedMethods: ["GET", "POST", "PUT", "DELETE"],
|
|
402
|
+
allowedHeaders: ["Content-Type", "Authorization"],
|
|
403
|
+
credentials: true,
|
|
404
|
+
exposeHeaders: ["Content-Length"],
|
|
405
|
+
}));
|
|
406
|
+
|
|
407
|
+
// Sintaxe alternativa: string + objeto
|
|
408
|
+
app.use(Middlewares.cors("https://meusite.com", {
|
|
409
|
+
allowedMethods: ["GET", "POST"],
|
|
410
|
+
credentials: true,
|
|
411
|
+
}));
|
|
347
412
|
```
|
|
348
413
|
|
|
349
|
-
|
|
350
|
-
|
|
414
|
+
**`CorsOptions`:**
|
|
415
|
+
|
|
416
|
+
| Propriedade | Tipo | Descrição |
|
|
417
|
+
|------------------|-----------------------------|------------------------------------------------------------------|
|
|
418
|
+
| `allowOrigin` | `string` | Origem permitida (`"*"` para todas) |
|
|
419
|
+
| `allowedMethods` | `string[] \| string` | Métodos HTTP permitidos |
|
|
420
|
+
| `allowedHeaders` | `string[] \| string` | Headers que o cliente pode enviar |
|
|
421
|
+
| `credentials` | `boolean` | Permite cookies e headers de autenticação |
|
|
422
|
+
| `exposeHeaders` | `string[] \| string` | Headers adicionais legíveis pelo cliente |
|
|
423
|
+
|
|
424
|
+
#### `Middlewares.files(...allowedMimes)`
|
|
425
|
+
|
|
426
|
+
Parsing de arquivos `multipart/form-data`. Os arquivos ficam disponíveis em `req.file` (primeiro) e `req.files` (todos).
|
|
351
427
|
|
|
352
428
|
```typescript
|
|
353
|
-
router
|
|
354
|
-
|
|
429
|
+
import { Middlewares } from "@ismael1361/router";
|
|
430
|
+
|
|
431
|
+
// Aceitar qualquer tipo de arquivo
|
|
432
|
+
app.post("/upload")
|
|
433
|
+
.handler(Middlewares.files())
|
|
355
434
|
.handler((req, res) => {
|
|
356
|
-
|
|
435
|
+
// req.file: FileInfo (primeiro arquivo)
|
|
436
|
+
// req.files: FileInfo[] (todos os arquivos)
|
|
437
|
+
res.json({
|
|
438
|
+
filename: req.file.originalname,
|
|
439
|
+
size: req.file.size,
|
|
440
|
+
mimetype: req.file.mimetype,
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Aceitar apenas imagens e PDFs
|
|
445
|
+
app.post("/upload-docs")
|
|
446
|
+
.handler(Middlewares.files("image/jpeg", "image/png", "application/pdf"))
|
|
447
|
+
.handler((req, res) => {
|
|
448
|
+
res.json({ count: req.files.length });
|
|
357
449
|
});
|
|
358
450
|
```
|
|
359
451
|
|
|
360
|
-
|
|
361
|
-
Anexa um roteador existente ao atual.
|
|
452
|
+
**`FileInfo`:**
|
|
362
453
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
454
|
+
| Propriedade | Tipo | Descrição |
|
|
455
|
+
|----------------|------------|-----------------------------|
|
|
456
|
+
| `fieldname` | `string` | Nome do campo do formulário |
|
|
457
|
+
| `originalname` | `string` | Nome original do arquivo |
|
|
458
|
+
| `mimetype` | `string` | Tipo MIME do arquivo |
|
|
459
|
+
| `size` | `number` | Tamanho em bytes |
|
|
460
|
+
| `buffer` | `Buffer` | Conteúdo do arquivo |
|
|
461
|
+
| `stream` | `Readable` | Stream legível |
|
|
366
462
|
|
|
367
|
-
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 🔷 Interfaces e Tipos
|
|
466
|
+
|
|
467
|
+
### `IApplication`
|
|
468
|
+
|
|
469
|
+
Estende `IRouter` com capacidades de servidor HTTP e sistema de stacks.
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
interface IApplication extends IRouter {
|
|
473
|
+
listen: express.Application["listen"];
|
|
474
|
+
disable: express.Application["disable"];
|
|
475
|
+
enable: express.Application["enable"];
|
|
476
|
+
disabled: express.Application["disabled"];
|
|
477
|
+
enabled: express.Application["enabled"];
|
|
478
|
+
engine: express.Application["engine"];
|
|
479
|
+
param: express.Application["param"];
|
|
480
|
+
render: express.Application["render"];
|
|
481
|
+
|
|
482
|
+
getStacks(): IStackLog[];
|
|
483
|
+
defineStacks(options?: IStacksOptions): { stacksPath: string };
|
|
484
|
+
}
|
|
368
485
|
```
|
|
369
486
|
|
|
370
|
-
|
|
371
|
-
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
### `IRouter`
|
|
490
|
+
|
|
491
|
+
Interface principal do router. Expõe métodos HTTP, sub-rotas, middlewares e configuração Swagger.
|
|
372
492
|
|
|
373
493
|
```typescript
|
|
374
|
-
|
|
494
|
+
interface IRouter extends RequestHandler {
|
|
495
|
+
// Métodos HTTP — retornam IHandler com parâmetros inferidos da rota
|
|
496
|
+
all: IRouterMatcher<"all">;
|
|
497
|
+
get: IRouterMatcher<"get">;
|
|
498
|
+
post: IRouterMatcher<"post">;
|
|
499
|
+
put: IRouterMatcher<"put">;
|
|
500
|
+
delete: IRouterMatcher<"delete">;
|
|
501
|
+
patch: IRouterMatcher<"patch">;
|
|
502
|
+
options: IRouterMatcher<"options">;
|
|
503
|
+
head: IRouterMatcher<"head">;
|
|
504
|
+
|
|
505
|
+
parent: IRouter | null;
|
|
506
|
+
path: string;
|
|
375
507
|
|
|
376
|
-
|
|
508
|
+
param: express.Application["param"];
|
|
377
509
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
title: 'Minha API',
|
|
382
|
-
version: '1.0.0',
|
|
383
|
-
description: 'API com documentação automática'
|
|
384
|
-
},
|
|
385
|
-
servers: [{ url: 'http://localhost:3000' }],
|
|
386
|
-
components: {
|
|
387
|
-
securitySchemes: {
|
|
388
|
-
bearerAuth: {
|
|
389
|
-
type: 'http',
|
|
390
|
-
scheme: 'bearer',
|
|
391
|
-
bearerFormat: 'JWT'
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
defaultResponses: {
|
|
396
|
-
400: { description: "Dados inválidos" },
|
|
397
|
-
401: {
|
|
398
|
-
description: "Falha na autenticação",
|
|
399
|
-
},
|
|
400
|
-
403: { description: "Acesso negado" },
|
|
401
|
-
500: { description: "Erro interno do servidor" },
|
|
402
|
-
},
|
|
403
|
-
};
|
|
510
|
+
route(prefix: string, doc?: MiddlewareFCDoc): IRouter;
|
|
511
|
+
route(prefix: string, router: IRouter, doc?: MiddlewareFCDoc): IRouter;
|
|
512
|
+
route(router: IRouter, doc?: MiddlewareFCDoc): IRouter;
|
|
404
513
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
514
|
+
use(prefix: string, doc?: MiddlewareFCDoc): IHandler;
|
|
515
|
+
use(prefix: string, handler: IRouter | RequestHandler, doc?: MiddlewareFCDoc): void;
|
|
516
|
+
use(handler: IRouter | RequestHandler, doc?: MiddlewareFCDoc): void;
|
|
517
|
+
|
|
518
|
+
defineSwagger(options: SwaggerOptions): void;
|
|
519
|
+
getSwagger(): swaggerJSDoc.Options;
|
|
520
|
+
}
|
|
409
521
|
```
|
|
410
522
|
|
|
411
|
-
|
|
523
|
+
---
|
|
412
524
|
|
|
413
|
-
###
|
|
525
|
+
### `IHandler`
|
|
526
|
+
|
|
527
|
+
Handler encadeável que combina execução de middlewares com documentação OpenAPI. Cada `.handler()` mescla tipos cumulativamente.
|
|
414
528
|
|
|
415
529
|
```typescript
|
|
416
|
-
|
|
530
|
+
interface IHandler<Rq extends Request, Rs extends Response> extends RequestHandler<Rq, Rs> {
|
|
531
|
+
handler<Req extends Request, Res extends Response>(
|
|
532
|
+
fn: RequestHandler<Req & Rq, Res & Rs> | IHandler<Req & Rq, Res & Rs>
|
|
533
|
+
): IHandler<JoinRequest<Rq, Req>, JoinResponse<Rs, Res>>;
|
|
534
|
+
|
|
535
|
+
doc(
|
|
536
|
+
operation: MiddlewareFCDoc | swaggerJSDoc.Operation,
|
|
537
|
+
components?: swaggerJSDoc.Components
|
|
538
|
+
): IHandler<Rq, Rs>;
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Encadeamento e mesclagem de tipos:**
|
|
417
543
|
|
|
544
|
+
```typescript
|
|
418
545
|
interface AuthRequest extends Request {
|
|
419
546
|
user: { id: string; roles: string[] };
|
|
420
547
|
}
|
|
421
548
|
|
|
422
|
-
|
|
423
|
-
const authenticate = middleware<AuthRequest>(
|
|
424
|
-
(req, res, next) => {
|
|
425
|
-
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
426
|
-
|
|
427
|
-
if (!token) {
|
|
428
|
-
return res.status(401).json({ message: 'Token não fornecido' });
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Validar token (exemplo simplificado)
|
|
432
|
-
req.user = { id: '123', roles: ['user'] };
|
|
433
|
-
next();
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
security: [{ bearerAuth: [] }],
|
|
437
|
-
responses: {
|
|
438
|
-
401: { description: 'Não autorizado' }
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
// Middleware de autorização
|
|
444
|
-
const authorize = (...roles: string[]) =>
|
|
445
|
-
middleware<AuthRequest>(
|
|
446
|
-
(req, res, next) => {
|
|
447
|
-
if (!req.user.roles.some(role => roles.includes(role))) {
|
|
448
|
-
return res.status(403).json({ message: 'Acesso negado' });
|
|
449
|
-
}
|
|
450
|
-
next();
|
|
451
|
-
},
|
|
452
|
-
{
|
|
453
|
-
responses: {
|
|
454
|
-
403: { description: 'Acesso negado' }
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
const app = create<AuthRequest>()
|
|
460
|
-
.middleware(Middlewares.json());
|
|
549
|
+
interface PaginatedRequest extends Request<string, any, { page: number; limit: number }> {}
|
|
461
550
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
.
|
|
465
|
-
.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
.doc({
|
|
471
|
-
summary: 'Listar usuários (Admin)',
|
|
472
|
-
tags: ['Admin'],
|
|
473
|
-
responses: { 200: { description: 'Lista de usuários' } }
|
|
551
|
+
app.get("/items")
|
|
552
|
+
.handler(authMiddleware) // req agora tem .user
|
|
553
|
+
.handler(paginationMiddleware) // req agora tem .user + .query.page + .query.limit
|
|
554
|
+
.handler((req, res) => {
|
|
555
|
+
// Todos os tipos estão disponíveis simultaneamente
|
|
556
|
+
console.log(req.user.id); // string
|
|
557
|
+
console.log(req.query.page); // number
|
|
558
|
+
res.json([]);
|
|
474
559
|
});
|
|
475
560
|
```
|
|
476
561
|
|
|
477
|
-
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
### `IMiddleware`
|
|
565
|
+
|
|
566
|
+
Middleware sem `.handler()`, apenas `.doc()`. Deve ser encadeado dentro de um `IHandler`.
|
|
478
567
|
|
|
479
568
|
```typescript
|
|
480
|
-
|
|
569
|
+
interface IMiddleware<Rq extends Request, Rs extends Response> extends RequestHandler<Rq, Rs> {
|
|
570
|
+
doc(
|
|
571
|
+
operation: MiddlewareFCDoc | swaggerJSDoc.Operation,
|
|
572
|
+
components?: swaggerJSDoc.Components
|
|
573
|
+
): IMiddleware<Rq, Rs>;
|
|
574
|
+
}
|
|
575
|
+
```
|
|
481
576
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
### `Request`
|
|
580
|
+
|
|
581
|
+
Estende `express.Request` com parâmetros genéricos tipados.
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
interface Request<
|
|
585
|
+
P extends string = string, // Parâmetros de rota
|
|
586
|
+
ReqBody = {}, // Corpo da requisição
|
|
587
|
+
ReqQuery = core.Query, // Query string
|
|
588
|
+
ResBody = any // Corpo da resposta
|
|
589
|
+
> extends core.Request<ParamsDictionary<P>, ResBody, ReqBody, ReqQuery> {
|
|
590
|
+
clientIp?: string;
|
|
591
|
+
executeOnce?: (isOnce?: boolean) => void;
|
|
488
592
|
}
|
|
593
|
+
```
|
|
489
594
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
return res.status(400).json({
|
|
498
|
-
message: 'Dados inválidos',
|
|
499
|
-
errors: result.error.errors
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
req.validated = { body: result.data };
|
|
504
|
-
next();
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
responses: {
|
|
508
|
-
400: { description: 'Dados de entrada inválidos' }
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
);
|
|
595
|
+
```typescript
|
|
596
|
+
// Parâmetros inferidos da rota
|
|
597
|
+
app.get("/users/:userId/posts/:postId")
|
|
598
|
+
.handler((req, res) => {
|
|
599
|
+
req.params.userId; // string ✓
|
|
600
|
+
req.params.postId; // string ✓
|
|
601
|
+
});
|
|
512
602
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
603
|
+
// Tipo explícito de body
|
|
604
|
+
interface CreateUser extends Request<string, { name: string; email: string }> {}
|
|
605
|
+
|
|
606
|
+
app.post("/users")
|
|
607
|
+
.handler((req: CreateUser, res) => {
|
|
608
|
+
req.body.name; // string ✓
|
|
609
|
+
req.body.email; // string ✓
|
|
519
610
|
});
|
|
520
611
|
```
|
|
521
612
|
|
|
522
|
-
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
### `Response`
|
|
616
|
+
|
|
617
|
+
Estende `express.Response`.
|
|
523
618
|
|
|
524
619
|
```typescript
|
|
525
|
-
|
|
526
|
-
|
|
620
|
+
interface Response<ResBody = any> extends core.Response<ResBody> {}
|
|
621
|
+
```
|
|
527
622
|
|
|
528
|
-
|
|
623
|
+
---
|
|
529
624
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
625
|
+
### `SwaggerOptions`
|
|
626
|
+
|
|
627
|
+
Configuração para geração de documentação OpenAPI.
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
interface SwaggerOptions extends swaggerJSDoc.OAS3Definition {
|
|
631
|
+
path?: string; // Prefixo das rotas de doc (default: "/doc")
|
|
632
|
+
defaultResponses?: Responses; // Respostas padrão para todas as rotas
|
|
633
|
+
targets?: SnippetTargets[]; // Linguagens para code snippets
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**`SnippetTargets` disponíveis:**
|
|
638
|
+
|
|
639
|
+
`c_libcurl`, `csharp_restsharp`, `csharp_httpclient`, `go_native`, `java_okhttp`, `java_unirest`, `javascript_jquery`, `javascript_xhr`, `node_native`, `node_request`, `node_unirest`, `objc_nsurlsession`, `ocaml_cohttp`, `php_curl`, `php_http1`, `php_http2`, `python_python3`, `python_requests`, `ruby_native`, `shell_curl`, `shell_httpie`, `shell_wget`, `swift_nsurlsession`
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## 🔀 Métodos HTTP
|
|
644
|
+
|
|
645
|
+
Todos os métodos HTTP retornam um `IHandler` com inferência automática de parâmetros de rota.
|
|
646
|
+
|
|
647
|
+
```typescript
|
|
648
|
+
// Assinatura
|
|
649
|
+
app.get<Path extends string>(path: Path, doc?: MiddlewareFCDoc): IHandler<Request<ExtractRouteParameters<Path>>>;
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Métodos disponíveis:** `get`, `post`, `put`, `delete`, `patch`, `options`, `head`, `all`
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
// GET — leitura de recursos
|
|
656
|
+
app.get("/status")
|
|
657
|
+
.handler((req, res) => {
|
|
658
|
+
res.json({ status: "ok" });
|
|
659
|
+
})
|
|
660
|
+
.doc({ tags: ["Health"], summary: "Status da API" });
|
|
661
|
+
|
|
662
|
+
// POST — criação de recursos
|
|
663
|
+
app.post("/users")
|
|
664
|
+
.handler((req, res) => {
|
|
665
|
+
res.status(201).json({ id: Date.now(), ...req.body });
|
|
534
666
|
})
|
|
535
667
|
.doc({
|
|
536
|
-
|
|
537
|
-
|
|
668
|
+
tags: ["Users"],
|
|
669
|
+
summary: "Criar usuário",
|
|
670
|
+
requestBody: {
|
|
671
|
+
required: true,
|
|
672
|
+
content: {
|
|
673
|
+
"application/json": {
|
|
674
|
+
schema: {
|
|
675
|
+
type: "object",
|
|
676
|
+
required: ["name", "email"],
|
|
677
|
+
properties: {
|
|
678
|
+
name: { type: "string" },
|
|
679
|
+
email: { type: "string", format: "email" },
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
responses: { 201: { description: "Usuário criado" } },
|
|
538
686
|
});
|
|
539
687
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
.
|
|
543
|
-
res.
|
|
688
|
+
// PUT — substituição completa
|
|
689
|
+
app.put("/users/:id")
|
|
690
|
+
.handler((req, res) => {
|
|
691
|
+
res.json({ id: req.params.id, ...req.body });
|
|
544
692
|
})
|
|
545
|
-
.doc({
|
|
546
|
-
|
|
547
|
-
|
|
693
|
+
.doc({ tags: ["Users"], summary: "Substituir usuário" });
|
|
694
|
+
|
|
695
|
+
// PATCH — atualização parcial
|
|
696
|
+
app.patch("/users/:id")
|
|
697
|
+
.handler((req, res) => {
|
|
698
|
+
res.json({ id: req.params.id, updated: true });
|
|
699
|
+
})
|
|
700
|
+
.doc({ tags: ["Users"], summary: "Atualizar usuário parcialmente" });
|
|
701
|
+
|
|
702
|
+
// DELETE — remoção
|
|
703
|
+
app.delete("/users/:id")
|
|
704
|
+
.handler((req, res) => {
|
|
705
|
+
res.sendStatus(204);
|
|
706
|
+
})
|
|
707
|
+
.doc({ tags: ["Users"], summary: "Remover usuário" });
|
|
708
|
+
|
|
709
|
+
// ALL — responde a qualquer método
|
|
710
|
+
app.all("/proxy/*")
|
|
711
|
+
.handler((req, res) => {
|
|
712
|
+
res.json({ method: req.method, url: req.url });
|
|
548
713
|
});
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
**Documentação inline via segundo argumento:**
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
app.post("/items", { tags: ["Items"], summary: "Criar item" })
|
|
720
|
+
.handler((req, res) => {
|
|
721
|
+
res.status(201).json({ id: 1 });
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## 🔗 Rotas e Sub-routers
|
|
728
|
+
|
|
729
|
+
### `.route()` — Sub-router com prefixo
|
|
730
|
+
|
|
731
|
+
```typescript
|
|
732
|
+
// Criar sub-router inline
|
|
733
|
+
const usersRoute = app.route("/users");
|
|
734
|
+
usersRoute.get("/").handler((req, res) => res.json([]));
|
|
735
|
+
usersRoute.get("/:id").handler((req, res) => res.json({ id: req.params.id }));
|
|
736
|
+
|
|
737
|
+
// Anexar router existente com documentação global
|
|
738
|
+
const v1 = router();
|
|
739
|
+
|
|
740
|
+
v1.get("/items")
|
|
741
|
+
.handler((req, res) => res.json([]))
|
|
742
|
+
.doc({ tags: ["Items"], summary: "Listar itens" });
|
|
743
|
+
|
|
744
|
+
v1.post("/items")
|
|
745
|
+
.handler((req, res) => res.status(201).json(req.body))
|
|
746
|
+
.doc({ tags: ["Items"], summary: "Criar item" });
|
|
747
|
+
|
|
748
|
+
// Documentação aplicada a todas as rotas do sub-router
|
|
749
|
+
app.route("/v1", v1, {
|
|
750
|
+
security: [{ bearerAuth: [] }],
|
|
751
|
+
responses: {
|
|
752
|
+
400: { description: "Dados inválidos" },
|
|
753
|
+
404: { description: "Não encontrado" },
|
|
754
|
+
},
|
|
755
|
+
});
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
### `.use()` — Middleware ou sub-router
|
|
759
|
+
|
|
760
|
+
```typescript
|
|
761
|
+
// Middleware global
|
|
762
|
+
app.use((req, res, next) => {
|
|
763
|
+
console.log(`${req.method} ${req.url}`);
|
|
764
|
+
next();
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
// Middleware em prefixo (retorna IHandler encadeável)
|
|
768
|
+
app.use("/api")
|
|
769
|
+
.handler((req, res, next) => {
|
|
770
|
+
console.log("Requisição na /api");
|
|
771
|
+
next();
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// Sub-router via use
|
|
775
|
+
const adminRouter = router();
|
|
776
|
+
app.use("/admin", adminRouter);
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### Organização modular
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
// routes/users.ts
|
|
783
|
+
import { router } from "@ismael1361/router";
|
|
784
|
+
|
|
785
|
+
export const usersRouter = router();
|
|
786
|
+
|
|
787
|
+
usersRouter.get("/")
|
|
788
|
+
.handler((req, res) => res.json([]))
|
|
789
|
+
.doc({ tags: ["Users"], summary: "Listar usuários" });
|
|
790
|
+
|
|
791
|
+
usersRouter.post("/")
|
|
792
|
+
.handler((req, res) => res.status(201).json(req.body))
|
|
793
|
+
.doc({ tags: ["Users"], summary: "Criar usuário" });
|
|
549
794
|
|
|
550
|
-
// routes/products.
|
|
551
|
-
|
|
552
|
-
|
|
795
|
+
// routes/products.ts
|
|
796
|
+
import { router } from "@ismael1361/router";
|
|
797
|
+
|
|
798
|
+
export const productsRouter = router();
|
|
799
|
+
|
|
800
|
+
productsRouter.get("/")
|
|
801
|
+
.handler((req, res) => res.json([]))
|
|
802
|
+
.doc({ tags: ["Products"], summary: "Listar produtos" });
|
|
553
803
|
|
|
554
804
|
// app.ts
|
|
555
|
-
import { create } from
|
|
556
|
-
import { usersRouter } from
|
|
557
|
-
import { productsRouter } from
|
|
805
|
+
import { create, Middlewares } from "@ismael1361/router";
|
|
806
|
+
import { usersRouter } from "./routes/users";
|
|
807
|
+
import { productsRouter } from "./routes/products";
|
|
808
|
+
|
|
809
|
+
const app = create();
|
|
810
|
+
app.use(Middlewares.json());
|
|
558
811
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
812
|
+
app.route("/users", usersRouter);
|
|
813
|
+
app.route("/products", productsRouter);
|
|
814
|
+
|
|
815
|
+
app.defineSwagger({
|
|
816
|
+
openapi: "3.0.0",
|
|
817
|
+
info: { title: "API Modular", version: "1.0.0" },
|
|
818
|
+
});
|
|
562
819
|
|
|
563
|
-
|
|
564
|
-
.by(usersRouter)
|
|
565
|
-
.by(productsRouter);
|
|
820
|
+
app.listen(3000);
|
|
566
821
|
```
|
|
567
822
|
|
|
823
|
+
---
|
|
824
|
+
|
|
568
825
|
## 📚 Documentação OpenAPI/Swagger
|
|
569
826
|
|
|
570
|
-
|
|
827
|
+
### `.doc()` — Documentação em handlers e middlewares
|
|
571
828
|
|
|
572
|
-
|
|
829
|
+
Anexa metadados OpenAPI sem alterar o fluxo de execução. Pode ser chamado em qualquer ponto da cadeia.
|
|
573
830
|
|
|
574
831
|
```typescript
|
|
575
|
-
|
|
832
|
+
app.get("/users/:userId")
|
|
833
|
+
.handler(authMiddleware)
|
|
834
|
+
.doc({
|
|
835
|
+
tags: ["Users"],
|
|
836
|
+
summary: "Buscar usuário por ID",
|
|
837
|
+
parameters: [
|
|
838
|
+
{ name: "userId", in: "path", required: true, schema: { type: "string" } },
|
|
839
|
+
],
|
|
840
|
+
})
|
|
841
|
+
.handler((req, res) => {
|
|
842
|
+
res.json({ userId: req.params.userId });
|
|
843
|
+
});
|
|
844
|
+
```
|
|
576
845
|
|
|
577
|
-
|
|
846
|
+
**`.doc()` com componentes:**
|
|
578
847
|
|
|
579
|
-
|
|
580
|
-
app
|
|
581
|
-
.
|
|
582
|
-
.
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
description: 'Retorna um usuário pelo ID',
|
|
588
|
-
tags: ['Users'],
|
|
589
|
-
params: {
|
|
590
|
-
id: {
|
|
591
|
-
description: 'ID do usuário',
|
|
592
|
-
type: 'string',
|
|
593
|
-
required: true,
|
|
594
|
-
example: '123'
|
|
595
|
-
}
|
|
848
|
+
```typescript
|
|
849
|
+
app.delete("/users/:id")
|
|
850
|
+
.handler(authMiddleware)
|
|
851
|
+
.doc(
|
|
852
|
+
{
|
|
853
|
+
tags: ["Users"],
|
|
854
|
+
summary: "Remover usuário",
|
|
855
|
+
security: [{ bearerAuth: [] }],
|
|
596
856
|
},
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
content: {
|
|
601
|
-
'application/json': {
|
|
602
|
-
schema: {
|
|
603
|
-
type: 'object',
|
|
604
|
-
properties: {
|
|
605
|
-
id: { type: 'string' },
|
|
606
|
-
name: { type: 'string' }
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
857
|
+
{
|
|
858
|
+
securitySchemes: {
|
|
859
|
+
bearerAuth: { type: "http", scheme: "bearer" },
|
|
611
860
|
},
|
|
612
|
-
|
|
613
|
-
|
|
861
|
+
},
|
|
862
|
+
)
|
|
863
|
+
.handler((req, res) => {
|
|
864
|
+
res.sendStatus(204);
|
|
614
865
|
});
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
### `.defineSwagger()` — Configuração completa
|
|
869
|
+
|
|
870
|
+
Habilita a geração de documentação e cria automaticamente as seguintes rotas:
|
|
871
|
+
|
|
872
|
+
| Rota | Descrição |
|
|
873
|
+
|-------------------------------|----------------------------------|
|
|
874
|
+
| `/doc/swagger` | Interface Swagger UI |
|
|
875
|
+
| `/doc/swagger/definition.json`| Spec OpenAPI JSON |
|
|
876
|
+
| `/doc/redoc` | Interface ReDoc |
|
|
877
|
+
| `/doc/markdown` | Documentação em Markdown |
|
|
878
|
+
| `/doc/.md` | Markdown raw |
|
|
615
879
|
|
|
616
|
-
|
|
880
|
+
```typescript
|
|
617
881
|
app.defineSwagger({
|
|
618
|
-
openapi:
|
|
882
|
+
openapi: "3.0.0",
|
|
619
883
|
info: {
|
|
620
|
-
title:
|
|
621
|
-
version:
|
|
622
|
-
description:
|
|
623
|
-
contact: {
|
|
624
|
-
name: 'Suporte',
|
|
625
|
-
email: 'suporte@exemplo.com'
|
|
626
|
-
}
|
|
884
|
+
title: "API de Exemplo",
|
|
885
|
+
version: "1.0.0",
|
|
886
|
+
description: "Documentação completa da API",
|
|
887
|
+
contact: { name: "Suporte", email: "suporte@example.com" },
|
|
627
888
|
},
|
|
628
889
|
servers: [
|
|
629
|
-
{
|
|
630
|
-
|
|
631
|
-
description: 'Servidor de desenvolvimento'
|
|
632
|
-
},
|
|
633
|
-
{
|
|
634
|
-
url: 'https://api.exemplo.com',
|
|
635
|
-
description: 'Servidor de produção'
|
|
636
|
-
}
|
|
890
|
+
{ url: "http://localhost:3000", description: "Desenvolvimento" },
|
|
891
|
+
{ url: "https://api.exemplo.com", description: "Produção" },
|
|
637
892
|
],
|
|
638
893
|
components: {
|
|
639
894
|
securitySchemes: {
|
|
640
895
|
bearerAuth: {
|
|
641
|
-
type:
|
|
642
|
-
scheme:
|
|
643
|
-
bearerFormat:
|
|
644
|
-
description: 'Token JWT no formato Bearer'
|
|
896
|
+
type: "http",
|
|
897
|
+
scheme: "bearer",
|
|
898
|
+
bearerFormat: "JWT",
|
|
645
899
|
},
|
|
646
|
-
|
|
647
|
-
type: 'apiKey',
|
|
648
|
-
in: 'header',
|
|
649
|
-
name: 'X-API-Key'
|
|
650
|
-
}
|
|
651
|
-
}
|
|
900
|
+
},
|
|
652
901
|
},
|
|
902
|
+
// Respostas de erro aplicadas a todas as rotas
|
|
653
903
|
defaultResponses: {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
904
|
+
400: { description: "Dados inválidos" },
|
|
905
|
+
401: { description: "Falha na autenticação" },
|
|
906
|
+
403: { description: "Acesso negado" },
|
|
907
|
+
500: { description: "Erro interno do servidor" },
|
|
908
|
+
},
|
|
909
|
+
// Linguagens de code snippets (opcional)
|
|
910
|
+
targets: ["shell_curl", "javascript_xhr", "node_native", "python_python3"],
|
|
657
911
|
});
|
|
912
|
+
```
|
|
658
913
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
914
|
+
### `.getSwagger()` — Obter spec programaticamente
|
|
915
|
+
|
|
916
|
+
```typescript
|
|
917
|
+
const spec = app.getSwagger();
|
|
918
|
+
console.log(JSON.stringify(spec.definition, null, 2));
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
923
|
+
## 📊 Sistema de Stacks (Logging)
|
|
924
|
+
|
|
925
|
+
Disponível apenas em `IApplication` (criado via `create()`). Registra erros, warnings e informações em arquivo de log, com UI HTML acessível por rota.
|
|
926
|
+
|
|
927
|
+
### `.defineStacks(options?)`
|
|
928
|
+
|
|
929
|
+
```typescript
|
|
930
|
+
interface IStacksOptions {
|
|
931
|
+
path?: string; // Rota da UI (default: "/stacks")
|
|
932
|
+
limit?: number; // Máximo de registros no arquivo (default: 100)
|
|
933
|
+
filePath?: string; // Caminho do arquivo de log (default: "./stacks.log")
|
|
934
|
+
beforeStack?(...stacks: IStackLog[]): Array<IStackLog | string | Error>;
|
|
935
|
+
}
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
```typescript
|
|
939
|
+
const { stacksPath } = app.defineStacks({
|
|
940
|
+
path: "/stacks",
|
|
941
|
+
limit: 200,
|
|
942
|
+
filePath: "./logs/stacks.log",
|
|
943
|
+
beforeStack(...stacks) {
|
|
944
|
+
// Filtrar ou transformar antes de salvar
|
|
945
|
+
return stacks.filter((s) => typeof s !== "string" && s.level === "ERROR");
|
|
946
|
+
},
|
|
663
947
|
});
|
|
948
|
+
|
|
949
|
+
console.log(`Stacks UI: http://localhost:3000${stacksPath}`);
|
|
664
950
|
```
|
|
665
951
|
|
|
666
|
-
|
|
952
|
+
Ao ativar stacks, `console.error()`, `console.warn()` e `console.info()` são interceptados automaticamente e registrados no arquivo de log. Erros não capturados (`unhandledRejection`, `uncaughtException`) também são registrados.
|
|
667
953
|
|
|
668
|
-
|
|
954
|
+
### `.getStacks()`
|
|
669
955
|
|
|
670
|
-
|
|
956
|
+
```typescript
|
|
957
|
+
const logs: IStackLog[] = app.getStacks();
|
|
958
|
+
logs.forEach((log) => {
|
|
959
|
+
console.log(`[${log.level}] ${log.name}: ${log.message} (${log.duration}ms)`);
|
|
960
|
+
});
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
**`IStackLog`:**
|
|
964
|
+
|
|
965
|
+
| Propriedade | Tipo | Descrição |
|
|
966
|
+
|--------------|---------------------------------------------|--------------------------------|
|
|
967
|
+
| `time` | `Date` | Timestamp do registro |
|
|
968
|
+
| `level` | `"ERROR" \| "WARN" \| "INFO" \| "DEBUG"` | Nível de severidade |
|
|
969
|
+
| `name` | `string` | Nome/categoria do log |
|
|
970
|
+
| `message` | `string` | Mensagem descritiva |
|
|
971
|
+
| `source` | `string` | Origem do log |
|
|
972
|
+
| `statusCode` | `number` | Código HTTP associado |
|
|
973
|
+
| `duration` | `number` | Duração em ms |
|
|
974
|
+
| `meta` | `string` | Metadados adicionais |
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
978
|
+
## 🎯 Exemplos Avançados
|
|
979
|
+
|
|
980
|
+
### Autenticação e Autorização
|
|
671
981
|
|
|
672
982
|
```typescript
|
|
673
|
-
import {
|
|
983
|
+
import { create, middleware, Middlewares, Request } from "@ismael1361/router";
|
|
674
984
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
user?: {
|
|
678
|
-
id: string;
|
|
679
|
-
email: string;
|
|
680
|
-
roles: string[];
|
|
681
|
-
};
|
|
682
|
-
requestId: string;
|
|
683
|
-
startTime: number;
|
|
985
|
+
interface AuthRequest extends Request {
|
|
986
|
+
user: { id: string; roles: string[] };
|
|
684
987
|
}
|
|
685
988
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
989
|
+
const authenticate = middleware((req: AuthRequest, res, next) => {
|
|
990
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
991
|
+
if (!token) {
|
|
992
|
+
res.status(401).json({ error: "Token não fornecido" });
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
req.user = { id: "123", roles: ["admin"] };
|
|
996
|
+
next();
|
|
997
|
+
}).doc({
|
|
998
|
+
security: [{ bearerAuth: [] }],
|
|
999
|
+
components: {
|
|
1000
|
+
securitySchemes: {
|
|
1001
|
+
bearerAuth: { type: "http", scheme: "bearer" },
|
|
1002
|
+
},
|
|
1003
|
+
},
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
const authorize = (...roles: string[]) =>
|
|
1007
|
+
middleware((req: AuthRequest, res, next) => {
|
|
1008
|
+
if (!req.user.roles.some((r) => roles.includes(r))) {
|
|
1009
|
+
res.status(403).json({ error: "Acesso negado" });
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
next();
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
const app = create();
|
|
1016
|
+
app.use(Middlewares.json());
|
|
1017
|
+
|
|
1018
|
+
app.get("/admin/users")
|
|
1019
|
+
.handler(authenticate)
|
|
1020
|
+
.handler(authorize("admin"))
|
|
1021
|
+
.handler((req, res) => {
|
|
1022
|
+
// req.user está tipado
|
|
1023
|
+
res.json({ adminId: req.user.id, users: [] });
|
|
1024
|
+
})
|
|
1025
|
+
.doc({
|
|
1026
|
+
tags: ["Admin"],
|
|
1027
|
+
summary: "Listar usuários (Admin)",
|
|
1028
|
+
responses: { 200: { description: "Lista de usuários" } },
|
|
1029
|
+
});
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
### Encadeamento de múltiplos handlers com tipos acumulados
|
|
1033
|
+
|
|
1034
|
+
```typescript
|
|
1035
|
+
interface AuthRequest extends Request {
|
|
1036
|
+
user: { userId: string; id: string; roles: string[] };
|
|
690
1037
|
}
|
|
691
1038
|
|
|
692
|
-
|
|
693
|
-
|
|
1039
|
+
const authMiddleware = middleware((req: AuthRequest, res, next) => {
|
|
1040
|
+
req.user = { userId: "123", id: "abc", roles: ["admin"] };
|
|
1041
|
+
next();
|
|
1042
|
+
}).doc({
|
|
1043
|
+
security: [{ bearerAuth: [] }],
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
app.get("/hello/:userId/:id")
|
|
1047
|
+
.handler(authMiddleware) // req ganha .user
|
|
1048
|
+
.handler((req, res, next) => {
|
|
1049
|
+
// req.user e req.params.userId/id estão disponíveis
|
|
1050
|
+
console.log(`Usuário: ${req.user.userId}`);
|
|
1051
|
+
next();
|
|
1052
|
+
})
|
|
1053
|
+
.doc({
|
|
1054
|
+
tags: ["Users"],
|
|
1055
|
+
summary: "Saudação personalizada",
|
|
1056
|
+
parameters: [
|
|
1057
|
+
{ name: "userId", in: "path", required: true, schema: { type: "string" } },
|
|
1058
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } },
|
|
1059
|
+
],
|
|
1060
|
+
})
|
|
1061
|
+
.handler((req, res) => {
|
|
1062
|
+
res.send(`Hello, ${req.params.userId}! ID: ${req.user.id}`);
|
|
1063
|
+
});
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
### Execução única de middleware
|
|
1067
|
+
|
|
1068
|
+
```typescript
|
|
1069
|
+
const expensiveMiddleware = middleware((req, res, next) => {
|
|
1070
|
+
req.executeOnce?.(); // Garante uma única execução por requisição
|
|
1071
|
+
console.log("Operação custosa executada uma vez");
|
|
1072
|
+
next();
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
// Mesmo aplicado em vários níveis, executa apenas uma vez
|
|
1076
|
+
app.use("/api")
|
|
1077
|
+
.handler(expensiveMiddleware)
|
|
1078
|
+
.handler((req, res, next) => { next(); });
|
|
694
1079
|
|
|
695
|
-
|
|
696
|
-
.
|
|
697
|
-
.
|
|
698
|
-
|
|
699
|
-
// res.sendSuccess está disponível
|
|
700
|
-
res.sendSuccess({ user: req.user });
|
|
1080
|
+
app.get("/api/data")
|
|
1081
|
+
.handler(expensiveMiddleware) // Não executa novamente
|
|
1082
|
+
.handler((req, res) => {
|
|
1083
|
+
res.json({ data: [] });
|
|
701
1084
|
});
|
|
702
1085
|
```
|
|
703
1086
|
|
|
704
|
-
###
|
|
1087
|
+
### Aplicação completa com sub-routers, Swagger e stacks
|
|
705
1088
|
|
|
706
1089
|
```typescript
|
|
707
|
-
import { Request } from
|
|
1090
|
+
import { create, router, middleware, Middlewares, Request } from "@ismael1361/router";
|
|
1091
|
+
|
|
1092
|
+
const app = create();
|
|
708
1093
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1094
|
+
app.use(Middlewares.json());
|
|
1095
|
+
app.use(Middlewares.cors({ allowOrigin: "*" }));
|
|
1096
|
+
|
|
1097
|
+
// --- Middleware de autenticação ---
|
|
1098
|
+
interface AuthRequest extends Request<"userId" | "id"> {
|
|
1099
|
+
user: { userId: string; id: string; roles: string[] };
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
const authMiddleware = middleware((req: AuthRequest, res, next) => {
|
|
1103
|
+
const { userId = "", id = "" } = req.params;
|
|
1104
|
+
req.user = { userId, id, roles: ["admin"] };
|
|
1105
|
+
next();
|
|
1106
|
+
}).doc({
|
|
1107
|
+
security: [{ bearerAuth: [] }],
|
|
1108
|
+
components: {
|
|
1109
|
+
securitySchemes: {
|
|
1110
|
+
bearerAuth: { type: "http", scheme: "bearer" },
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
// --- Rota direta na aplicação ---
|
|
1116
|
+
app.get("/hello/:userId/:id")
|
|
1117
|
+
.handler(authMiddleware)
|
|
1118
|
+
.handler((req, res, next) => {
|
|
1119
|
+
console.log(`Hello, ${req.user.id}!`);
|
|
1120
|
+
next();
|
|
1121
|
+
})
|
|
1122
|
+
.doc({ tags: ["Users"] })
|
|
1123
|
+
.handler((req, res) => {
|
|
1124
|
+
res.send(`Hello, ${req.params.userId}! ID: ${req.user.userId}`);
|
|
1125
|
+
})
|
|
1126
|
+
.doc({
|
|
1127
|
+
summary: "Saudação com autenticação",
|
|
1128
|
+
parameters: [
|
|
1129
|
+
{ name: "userId", in: "path", required: true, schema: { type: "string" } },
|
|
1130
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } },
|
|
1131
|
+
],
|
|
718
1132
|
});
|
|
1133
|
+
|
|
1134
|
+
// --- Sub-router v1 ---
|
|
1135
|
+
const v1 = router();
|
|
1136
|
+
|
|
1137
|
+
v1.get("/test/route")
|
|
1138
|
+
.handler((req, res) => {
|
|
1139
|
+
res.send("Hello from route!");
|
|
1140
|
+
})
|
|
1141
|
+
.doc({ tags: ["V1"], summary: "Rota de teste v1" });
|
|
1142
|
+
|
|
1143
|
+
app.route("/v1", v1, {
|
|
1144
|
+
security: [{ bearerAuth: [] }],
|
|
1145
|
+
responses: {
|
|
1146
|
+
400: { description: "Account not found" },
|
|
1147
|
+
404: { description: "Not found" },
|
|
1148
|
+
},
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
// --- Swagger ---
|
|
1152
|
+
app.defineSwagger({
|
|
1153
|
+
openapi: "3.0.0",
|
|
1154
|
+
info: { title: "My API", version: "1.0.0" },
|
|
1155
|
+
defaultResponses: {
|
|
1156
|
+
400: { description: "Dados inválidos" },
|
|
1157
|
+
401: { description: "Falha na autenticação" },
|
|
1158
|
+
403: { description: "Acesso negado" },
|
|
1159
|
+
500: { description: "Erro interno do servidor" },
|
|
1160
|
+
},
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
// --- Stacks ---
|
|
1164
|
+
app.defineStacks({
|
|
1165
|
+
path: "/stacks",
|
|
1166
|
+
limit: 100,
|
|
1167
|
+
filePath: "./stacks.log",
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
app.listen(8080, () => {
|
|
1171
|
+
console.log("Server: http://localhost:8080");
|
|
1172
|
+
console.log("Swagger: http://localhost:8080/doc/swagger");
|
|
1173
|
+
console.log("ReDoc: http://localhost:8080/doc/redoc");
|
|
1174
|
+
console.log("Stacks: http://localhost:8080/stacks");
|
|
1175
|
+
});
|
|
719
1176
|
```
|
|
720
1177
|
|
|
721
|
-
|
|
1178
|
+
---
|
|
722
1179
|
|
|
723
|
-
|
|
1180
|
+
## 🤝 Contribuindo
|
|
724
1181
|
|
|
725
1182
|
1. Faça um fork do projeto
|
|
726
1183
|
2. Crie uma branch para sua feature (`git checkout -b feature/MinhaFeature`)
|
|
@@ -732,12 +1189,6 @@ Contribuições são bem-vindas! Por favor, siga estas etapas:
|
|
|
732
1189
|
|
|
733
1190
|
Este projeto está sob a licença MIT. Veja o arquivo [LICENSE](MIT) para mais detalhes.
|
|
734
1191
|
|
|
735
|
-
## 🙏 Agradecimentos
|
|
736
|
-
|
|
737
|
-
- Express.js pela base sólida
|
|
738
|
-
- Swagger/OpenAPI pela especificação de documentação
|
|
739
|
-
- A comunidade TypeScript
|
|
740
|
-
|
|
741
1192
|
---
|
|
742
1193
|
|
|
743
|
-
Desenvolvido com ❤️ por [Ismael Souza Silva](https://github.com/ismael1361)
|
|
1194
|
+
Desenvolvido com ❤️ por [Ismael Souza Silva](https://github.com/ismael1361)
|