@l337quez/nest-swagger-zen 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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "workbench.colorCustomizations": {}
3
+ }
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Nest Swagger Zen 🐼
2
+
3
+ ![Nest Swagger Zen Portada](./assets/nest-swagger-zen.png)
4
+
5
+ Una librería genérica y estilizada para NestJS que te ayudará a limpiar tus controladores y modularizar la documentación de tu API de forma elegante. Con `nest-swagger-zen`, ya no tendrás que definir archivos pesados de configuración llenos de esquemas JSON.
6
+
7
+ ## Características ✨
8
+ - **100% Nest-Ready**: Utiliza las convenciones nativas de `@nestjs/swagger` y `applyDecorators`.
9
+ - **Limpieza visual**: Configura `ApiOperation`, `ApiResponse`, `ApiBody` y parámetros paginados en un **solo** bloque de configuración limpio y fuertemente tipado.
10
+ - **Adiós JSON schemas manuales**: Al usar DTOs, NestJS se encarga de autogenerar los JSON.
11
+
12
+ ## Instalación 📦
13
+
14
+ Al no estar en el registro público todavía, puedes instalar la librería en tus proyectos Nest referenciando rutas relativas o absolutas:
15
+
16
+ ```bash
17
+ npm install nest-swagger-zen
18
+ ```
19
+
20
+
21
+ ## Uso 🚀
22
+
23
+ ### 1. Reemplaza tus JSON manuales con Clases de Datos (DTOs o Modelos)
24
+ En lugar de crear constantes masivas que exportan `schema: { type: 'object' ... }`, utiliza clases junto con los decoradores centralizados de esta librería.
25
+
26
+ > *Nota: Swagger es agnóstico a la arquitectura. Puedes usar `@ZenProperty()` tanto en tus **DTOs** como directamente en los **Modelos o Entidades** de tu base de datos (Mongoose, TypeORM, etc).*
27
+
28
+ Crea tus clases para Request (**Body**) o para la respuesta (**Response**) usando `@ZenProperty()`:
29
+
30
+ ```typescript
31
+ // dto/user.dto.ts
32
+ import { ZenProperty, ZenPropertyOptional } from 'nest-swagger-zen';
33
+
34
+ export class CreateUserDto {
35
+ @ZenProperty({ example: 'juan@cliente.com', description: 'Correo electrónico' })
36
+ email: string;
37
+
38
+ @ZenProperty({ example: 'Juan Pérez' })
39
+ name: string;
40
+
41
+ @ZenPropertyOptional({ description: 'Edad del usuario', example: 28 })
42
+ age?: number;
43
+ }
44
+
45
+ export class UserResponseDto {
46
+ @ZenProperty({ example: 'User registered successfully' })
47
+ message: string;
48
+ }
49
+ ```
50
+
51
+ ### 2. Extrae la Configuración a un archivo externo (Patrón Zen)
52
+ La idea de esta librería es que tu controlador quede **100% libre de configuraciones**. Crea un archivo de definiciones (por ejemplo `swagger/user.swagger.ts`) donde guardarás toda la metadata, generando decoradores pre-configurados:
53
+
54
+ ```typescript
55
+ // swagger/user.swagger.ts
56
+ import { ZenSwagger } from 'nest-swagger-zen';
57
+ import { CreateUserDto, UserResponseDto } from '../dto/user.dto';
58
+
59
+ // Creas una constante que ya contiene el decorador listo
60
+ export const CreateUserDocs = () => ZenSwagger({
61
+ summary: 'Create User',
62
+ description: 'Endpoint to create a new user in the system.',
63
+ status: 201,
64
+ body: CreateUserDto,
65
+ response: UserResponseDto
66
+ });
67
+ ```
68
+
69
+ ### 3. Aplica tus nuevos decoradores al Controlador
70
+ Ahora, importa este decorador en tu controller. Fíjate cómo la lógica de tu endpoint queda absolutamente inmaculada:
71
+
72
+ ```typescript
73
+ // user.controller.ts
74
+ import { Controller, Post, Body } from '@nestjs/common';
75
+ import { CreateUserDocs } from './swagger/user.swagger';
76
+ import { CreateUserDto } from './dto/user.dto';
77
+
78
+ @Controller('users')
79
+ export class UserController {
80
+
81
+ @Post()
82
+ @CreateUserDocs()
83
+ create(@Body() payload: CreateUserDto) {
84
+ return { message: "User registered successfully" };
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## Configuración ⚙️
90
+
91
+ La interfaz `ZenSwaggerConfig` que puedes enviarle a `@ZenSwagger()` soporta abarcar toda la casuística de tu API de manera sencilla:
92
+
93
+ - `summary` *(string, requerido)*: Título breve del endpoint.
94
+ - `description` *(string, opcional)*: Descripción extendida.
95
+ - `deprecated` *(boolean, opcional)*: Si se envía `true`, el endpoint aparecerá tachado en Swagger indicando que obsoleto.
96
+ - `status` *(number, opcional)*: Código HTTP retornado al tener éxito (Default `200`).
97
+ - `body` *(Type, opcional)*: Clase DTO para construir el modelo Swagger JSON del `body`.
98
+ - `response` *(Type, opcional)*: Clase DTO para construir el modelo Swagger JSON de la respuesta.
99
+ - `example` *(any, opcional)*: Valor puro a renderizar como respuesta de ejemplo (para respuestas primitivas).
100
+ - `isPaginated` *(boolean, opcional)*: Si se envía `true`, agrega automáticamente los parámetros `page` y `limit`.
101
+ - `isBearerAuth` *(boolean, opcional)*: Si se envía `true`, añade el requerimiento del token JWT (`@ApiBearerAuth`).
102
+ - `params` *(array, opcional)*: Arreglo de objetos para documentar variables en la URL. Ej: `[{ name: 'id', description: 'ID de usuario' }]`.
103
+ - `queries` *(array, opcional)*: Arreglo para mapear QueryStrings libres. Ej: `[{ name: 'search', required: false }]`.
104
+ - `consumes` *(array de strings, opt)*: Útil para subida de archivos. Ej: `['multipart/form-data']`.
105
+ - `exclude` *(boolean, opcional)*: Oculta el endpoint del UI de Swagger.
Binary file
@@ -0,0 +1,3 @@
1
+ import { ApiPropertyOptions } from '@nestjs/swagger';
2
+ export declare function ZenProperty(options?: ApiPropertyOptions): PropertyDecorator;
3
+ export declare function ZenPropertyOptional(options?: ApiPropertyOptions): PropertyDecorator;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZenProperty = ZenProperty;
4
+ exports.ZenPropertyOptional = ZenPropertyOptional;
5
+ const swagger_1 = require("@nestjs/swagger");
6
+ function ZenProperty(options) {
7
+ return (0, swagger_1.ApiProperty)(options);
8
+ }
9
+ function ZenPropertyOptional(options) {
10
+ return (0, swagger_1.ApiPropertyOptional)(options);
11
+ }
12
+ //# sourceMappingURL=property.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property.decorator.js","sourceRoot":"","sources":["../../src/decorators/property.decorator.ts"],"names":[],"mappings":";;AAOA,kCAEC;AAMD,kDAEC;AAjBD,6CAAuF;AAOvF,SAAgB,WAAW,CAAC,OAA4B;IACtD,OAAO,IAAA,qBAAW,EAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAMD,SAAgB,mBAAmB,CAAC,OAA4B;IAC9D,OAAO,IAAA,6BAAmB,EAAC,OAAO,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { Type } from '@nestjs/common';
2
+ import { ApiParamOptions } from '@nestjs/swagger/dist/decorators/api-param.decorator';
3
+ import { ApiQueryOptions } from '@nestjs/swagger/dist/decorators/api-query.decorator';
4
+ export interface ZenSwaggerConfig {
5
+ summary: string;
6
+ description?: string;
7
+ deprecated?: boolean;
8
+ status?: number;
9
+ body?: Type<any>;
10
+ response?: Type<any>;
11
+ example?: any;
12
+ isPaginated?: boolean;
13
+ isBearerAuth?: boolean;
14
+ params?: ApiParamOptions[];
15
+ queries?: ApiQueryOptions[];
16
+ consumes?: string[];
17
+ exclude?: boolean;
18
+ }
19
+ export declare function ZenSwagger(config: ZenSwaggerConfig): <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZenSwagger = ZenSwagger;
4
+ const common_1 = require("@nestjs/common");
5
+ const swagger_1 = require("@nestjs/swagger");
6
+ function ZenSwagger(config) {
7
+ const decorators = [];
8
+ if (config.exclude) {
9
+ decorators.push((0, swagger_1.ApiExcludeEndpoint)());
10
+ }
11
+ decorators.push((0, swagger_1.ApiOperation)({
12
+ summary: config.summary,
13
+ description: config.description,
14
+ deprecated: config.deprecated,
15
+ }));
16
+ if (config.isBearerAuth) {
17
+ decorators.push((0, swagger_1.ApiBearerAuth)());
18
+ }
19
+ if (config.consumes && config.consumes.length > 0) {
20
+ decorators.push((0, swagger_1.ApiConsumes)(...config.consumes));
21
+ }
22
+ if (config.response) {
23
+ decorators.push((0, swagger_1.ApiResponse)({
24
+ status: config.status || 200,
25
+ description: config.summary,
26
+ type: config.response,
27
+ }));
28
+ }
29
+ else if (config.example) {
30
+ decorators.push((0, swagger_1.ApiResponse)({
31
+ status: config.status || 200,
32
+ description: config.summary,
33
+ content: {
34
+ 'application/json': {
35
+ example: config.example,
36
+ },
37
+ },
38
+ }));
39
+ }
40
+ else {
41
+ decorators.push((0, swagger_1.ApiResponse)({
42
+ status: config.status || 200,
43
+ description: config.summary,
44
+ }));
45
+ }
46
+ if (config.body) {
47
+ decorators.push((0, swagger_1.ApiBody)({ type: config.body }));
48
+ }
49
+ if (config.isPaginated) {
50
+ decorators.push((0, swagger_1.ApiQuery)({ name: 'page', required: false, type: Number, example: 1 }), (0, swagger_1.ApiQuery)({ name: 'limit', required: false, type: Number, example: 10 }));
51
+ }
52
+ if (config.params && config.params.length > 0) {
53
+ config.params.forEach((param) => decorators.push((0, swagger_1.ApiParam)(param)));
54
+ }
55
+ if (config.queries && config.queries.length > 0) {
56
+ config.queries.forEach((query) => decorators.push((0, swagger_1.ApiQuery)(query)));
57
+ }
58
+ return (0, common_1.applyDecorators)(...decorators);
59
+ }
60
+ //# sourceMappingURL=swagger.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swagger.decorator.js","sourceRoot":"","sources":["../../src/decorators/swagger.decorator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './decorators/swagger.decorator';
2
+ export * from './decorators/property.decorator';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./decorators/swagger.decorator"), exports);
18
+ __exportStar(require("./decorators/property.decorator"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA+C;AAC/C,kEAAgD"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@l337quez/nest-swagger-zen",
3
+ "version": "1.0.0",
4
+ "description": "A stylish, generalized library to prevent Swagger from cluttering NestJS controllers.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "echo \"Error: no test specified\" && exit 1",
10
+ "prepare": "npm run build"
11
+ },
12
+ "keywords": [
13
+ "nestjs",
14
+ "swagger",
15
+ "decorators",
16
+ "zen"
17
+ ],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "devDependencies": {
21
+ "@nestjs/common": "^10.0.0",
22
+ "@nestjs/swagger": "^7.0.0",
23
+ "@types/node": "^20.0.0",
24
+ "reflect-metadata": "^0.1.0",
25
+ "rxjs": "^7.0.0",
26
+ "ts-node": "^10.9.2",
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "peerDependencies": {
30
+ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
31
+ "@nestjs/swagger": "^6.0.0 || ^7.0.0"
32
+ }
33
+ }