mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-18 20:21:24 +02:00
feat(swagger): add OpenAPI documentation to calendar, contacts, and todo backends
- Extend shared-nestjs-setup bootstrapApp with optional swagger config - Auto-setup Swagger/OpenAPI when swagger: true is passed - Add @nestjs/swagger as optional peer dependency - Enable swagger in calendar (:3014/api/docs), contacts (:3015/api/docs), todo (:3018/api/docs) - Migrate todo main.ts from custom bootstrap to shared bootstrapApp - JWT Bearer auth configured in Swagger UI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4c342a53e8
commit
217c48663b
9 changed files with 94 additions and 69 deletions
|
|
@ -33,6 +33,7 @@
|
|||
"@nestjs/core": "^10.4.15",
|
||||
"@nestjs/platform-express": "^10.4.15",
|
||||
"@nestjs/schedule": "^4.1.2",
|
||||
"@nestjs/swagger": "^11.2.6",
|
||||
"@nestjs/throttler": "^6.2.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ bootstrapApp(AppModule, {
|
|||
defaultPort: 3014,
|
||||
serviceName: 'Calendar',
|
||||
additionalCorsOrigins: ['http://localhost:5179'],
|
||||
swagger: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
"@nestjs/config": "^3.3.0",
|
||||
"@nestjs/core": "^10.4.15",
|
||||
"@nestjs/platform-express": "^10.4.15",
|
||||
"@nestjs/swagger": "^11.2.6",
|
||||
"@nestjs/throttler": "^6.2.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ bootstrapApp(AppModule, {
|
|||
defaultPort: 3015,
|
||||
serviceName: 'Contacts',
|
||||
additionalCorsOrigins: ['http://localhost:5184'],
|
||||
swagger: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
"@nestjs/core": "^10.4.9",
|
||||
"@nestjs/platform-express": "^10.4.9",
|
||||
"@nestjs/schedule": "^4.1.2",
|
||||
"@nestjs/swagger": "^11.2.6",
|
||||
"@nestjs/throttler": "^6.2.1",
|
||||
"@todo/shared": "workspace:*",
|
||||
"class-transformer": "^0.5.1",
|
||||
|
|
|
|||
|
|
@ -1,67 +1,9 @@
|
|||
import { NestFactory } from '@nestjs/core';
|
||||
import { ValidationPipe, Logger } from '@nestjs/common';
|
||||
import { bootstrapApp } from '@manacore/shared-nestjs-setup';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const logger = new Logger('Bootstrap');
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// Enable CORS for all platforms
|
||||
app.enableCors({
|
||||
origin: (origin, callback) => {
|
||||
// Allow requests with no origin (mobile apps, curl, etc.)
|
||||
if (!origin) {
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
const allowedOrigins = process.env.CORS_ORIGINS?.split(',') || [
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5186',
|
||||
'http://localhost:8081',
|
||||
'http://localhost:19006',
|
||||
];
|
||||
|
||||
// Allow all localhost ports in development
|
||||
if (process.env.NODE_ENV === 'development' && origin.includes('localhost')) {
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowedOrigins.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
logger.warn(`Blocked request from origin: ${origin}`);
|
||||
callback(new Error('Not allowed by CORS'), false);
|
||||
}
|
||||
},
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
});
|
||||
|
||||
// Global validation pipe
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
transform: true,
|
||||
transformOptions: {
|
||||
enableImplicitConversion: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// API prefix (exclude metrics endpoint for Prometheus scraping)
|
||||
app.setGlobalPrefix('api/v1', {
|
||||
exclude: ['metrics', 'health'],
|
||||
});
|
||||
|
||||
const port = process.env.PORT || 3017;
|
||||
await app.listen(port);
|
||||
|
||||
logger.log(`Todo API is running on: http://localhost:${port}`);
|
||||
logger.log(`Health check: http://localhost:${port}/health`);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
bootstrapApp(AppModule, {
|
||||
defaultPort: 3018,
|
||||
serviceName: 'Todo',
|
||||
additionalCorsOrigins: ['http://localhost:5186', 'http://localhost:5188'],
|
||||
swagger: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/swagger": "^8.0.0 || ^7.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nestjs/swagger": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* Shared NestJS Bootstrap Utilities for ManaCore Backends
|
||||
*
|
||||
* Provides a consistent setup for CORS, validation, and global prefix
|
||||
* across all backend applications.
|
||||
* Provides a consistent setup for CORS, validation, global prefix,
|
||||
* and optional Swagger/OpenAPI documentation across all backend applications.
|
||||
*/
|
||||
|
||||
import { type INestApplication, ValidationPipe, type Type } from '@nestjs/common';
|
||||
|
|
@ -21,6 +21,20 @@ export const DEFAULT_CORS_ORIGINS = [
|
|||
'exp://localhost:8081', // Expo native
|
||||
];
|
||||
|
||||
/**
|
||||
* Swagger/OpenAPI configuration
|
||||
*/
|
||||
export interface SwaggerOptions {
|
||||
/** API title (default: serviceName + ' API') */
|
||||
title?: string;
|
||||
/** API description */
|
||||
description?: string;
|
||||
/** API version (default: '1.0') */
|
||||
version?: string;
|
||||
/** Path to serve docs at (default: 'api/docs') */
|
||||
path?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration options for the bootstrap utility
|
||||
*/
|
||||
|
|
@ -39,6 +53,8 @@ export interface BootstrapOptions {
|
|||
corsMethods?: string[];
|
||||
/** Body size limit for JSON/urlencoded payloads (default: '100kb'). Use '50mb' for image uploads. */
|
||||
bodyLimit?: string;
|
||||
/** Enable Swagger/OpenAPI docs. Pass true for defaults or SwaggerOptions for custom config. */
|
||||
swagger?: boolean | SwaggerOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -93,6 +109,38 @@ export function configurePrefix(
|
|||
app.setGlobalPrefix(prefix, { exclude });
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Swagger/OpenAPI documentation if enabled and @nestjs/swagger is installed
|
||||
*/
|
||||
async function setupSwagger(
|
||||
app: INestApplication,
|
||||
serviceName: string,
|
||||
port: string | number,
|
||||
swaggerConfig: boolean | SwaggerOptions
|
||||
): Promise<void> {
|
||||
try {
|
||||
const { DocumentBuilder, SwaggerModule } = await import('@nestjs/swagger');
|
||||
const opts: SwaggerOptions = typeof swaggerConfig === 'object' ? swaggerConfig : {};
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle(opts.title || `${serviceName} API`)
|
||||
.setDescription(opts.description || `API documentation for ${serviceName}`)
|
||||
.setVersion(opts.version || '1.0')
|
||||
.addBearerAuth({ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }, 'JWT-auth')
|
||||
.build();
|
||||
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
const docsPath = opts.path || 'api/docs';
|
||||
SwaggerModule.setup(docsPath, app, document, {
|
||||
swaggerOptions: { persistAuthorization: true },
|
||||
});
|
||||
|
||||
console.log(`${serviceName} API docs at http://localhost:${port}/${docsPath}`);
|
||||
} catch {
|
||||
// @nestjs/swagger not installed - skip silently
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap a NestJS application with standard configuration
|
||||
*
|
||||
|
|
@ -105,6 +153,7 @@ export function configurePrefix(
|
|||
* defaultPort: 3002,
|
||||
* serviceName: 'Chat',
|
||||
* additionalCorsOrigins: ['http://localhost:5178'],
|
||||
* swagger: true,
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
|
@ -135,8 +184,13 @@ export async function bootstrapApp(
|
|||
options.excludeFromPrefix ?? ['metrics', 'health']
|
||||
);
|
||||
|
||||
// Start listening
|
||||
// Setup Swagger/OpenAPI docs if enabled
|
||||
const port = process.env.PORT || options.defaultPort;
|
||||
if (options.swagger) {
|
||||
await setupSwagger(app, options.serviceName, port, options.swagger);
|
||||
}
|
||||
|
||||
// Start listening
|
||||
await app.listen(port);
|
||||
|
||||
console.log(`${options.serviceName} backend running on http://localhost:${port}`);
|
||||
|
|
|
|||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
|
|
@ -467,6 +467,9 @@ importers:
|
|||
'@nestjs/platform-express':
|
||||
specifier: ^10.4.15
|
||||
version: 10.4.20(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)
|
||||
'@nestjs/throttler':
|
||||
specifier: ^6.2.1
|
||||
version: 6.4.0(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)(reflect-metadata@0.2.2)
|
||||
class-transformer:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
|
|
@ -1300,6 +1303,9 @@ importers:
|
|||
'@manacore/shared-vite-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-vite-config
|
||||
'@playwright/test':
|
||||
specifier: ^1.52.0
|
||||
version: 1.57.0
|
||||
'@sveltejs/adapter-node':
|
||||
specifier: ^5.0.0
|
||||
version: 5.4.0(@sveltejs/kit@2.49.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.44.0)(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.44.0)(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.1)))
|
||||
|
|
@ -2726,6 +2732,9 @@ importers:
|
|||
'@nestjs/platform-express':
|
||||
specifier: ^10.4.15
|
||||
version: 10.4.20(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)
|
||||
'@nestjs/throttler':
|
||||
specifier: ^6.2.1
|
||||
version: 6.4.0(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)(reflect-metadata@0.2.2)
|
||||
class-transformer:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
|
|
@ -3487,6 +3496,9 @@ importers:
|
|||
'@nestjs/platform-express':
|
||||
specifier: ^10.4.15
|
||||
version: 10.4.20(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)
|
||||
'@nestjs/throttler':
|
||||
specifier: ^6.2.1
|
||||
version: 6.4.0(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)(reflect-metadata@0.2.2)
|
||||
class-transformer:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1
|
||||
|
|
@ -5324,6 +5336,9 @@ importers:
|
|||
'@manacore/shared-vite-config':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../packages/shared-vite-config
|
||||
'@playwright/test':
|
||||
specifier: ^1.52.0
|
||||
version: 1.57.0
|
||||
'@sveltejs/adapter-node':
|
||||
specifier: ^5.0.0
|
||||
version: 5.4.0(@sveltejs/kit@2.49.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.44.0)(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.1)))(svelte@5.44.0)(vite@6.4.1(@types/node@20.19.25)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.1)))
|
||||
|
|
@ -6423,6 +6438,9 @@ importers:
|
|||
'@nestjs/core':
|
||||
specifier: ^10.0.0 || ^11.0.0
|
||||
version: 10.4.20(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.20)(@nestjs/websockets@10.4.20)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@nestjs/swagger':
|
||||
specifier: ^8.0.0 || ^7.0.0
|
||||
version: 8.1.1(@nestjs/common@10.4.20(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.20)(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)
|
||||
express:
|
||||
specifier: ^4.21.0
|
||||
version: 4.21.2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue