feat(openapi): Add OpenAPI module: decorators, spec generator, runtime validation and Swagger UI
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
* Controller registry - stores all registered controllers
|
||||
*/
|
||||
|
||||
import type { IControllerMetadata, IRegisteredController, ICompiledRoute } from './decorators.types.js';
|
||||
import type { IControllerMetadata, IRegisteredController, ICompiledRoute, IOpenApiRouteMeta } from './decorators.types.js';
|
||||
import type { IRequestContext, IInterceptOptions, THttpMethod } from '../core/smartserve.interfaces.js';
|
||||
import { getControllerMetadata, combinePaths } from './decorators.metadata.js';
|
||||
import { createValidationInterceptor } from '../openapi/openapi.validator.js';
|
||||
|
||||
/**
|
||||
* Global registry of all controllers
|
||||
@@ -92,7 +93,7 @@ export class ControllerRegistry {
|
||||
/**
|
||||
* Compile all routes for fast matching
|
||||
*/
|
||||
static compileRoutes(): ICompiledRoute[] {
|
||||
static compileRoutes(enableValidation = true): ICompiledRoute[] {
|
||||
if (this.routesCompiled) {
|
||||
return this.compiledRoutes;
|
||||
}
|
||||
@@ -105,10 +106,19 @@ export class ControllerRegistry {
|
||||
const { regex, paramNames } = this.pathToRegex(fullPath);
|
||||
|
||||
// Combine class and method interceptors
|
||||
const interceptors: IInterceptOptions[] = [
|
||||
...metadata.classInterceptors,
|
||||
...route.interceptors,
|
||||
];
|
||||
const interceptors: IInterceptOptions[] = [];
|
||||
|
||||
// Add OpenAPI validation interceptor first (before other interceptors)
|
||||
// This ensures validation happens before any other processing
|
||||
if (enableValidation && route.openapi && this.hasValidationMetadata(route.openapi)) {
|
||||
interceptors.push({
|
||||
request: createValidationInterceptor(route.openapi),
|
||||
});
|
||||
}
|
||||
|
||||
// Then add class-level and method-level interceptors
|
||||
interceptors.push(...metadata.classInterceptors);
|
||||
interceptors.push(...route.interceptors);
|
||||
|
||||
// Create bound handler
|
||||
const handler = async (ctx: IRequestContext): Promise<any> => {
|
||||
@@ -127,6 +137,7 @@ export class ControllerRegistry {
|
||||
handler,
|
||||
interceptors,
|
||||
compression: route.compression,
|
||||
openapi: route.openapi,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -214,6 +225,18 @@ export class ControllerRegistry {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if OpenAPI metadata contains validation-relevant information
|
||||
*/
|
||||
private static hasValidationMetadata(openapi: IOpenApiRouteMeta): boolean {
|
||||
return !!(
|
||||
openapi.requestBody ||
|
||||
(openapi.params && openapi.params.size > 0) ||
|
||||
(openapi.query && openapi.query.size > 0) ||
|
||||
(openapi.headers && openapi.headers.size > 0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all registered controllers (useful for testing)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user