diff --git a/README.md b/README.md index 9d80f08..bc1bae6 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ app.run(); // Open http://localhost:3030/api/docs | `path` | `'/api/docs'` | Mount path for Swagger UI; value is used as-is. | | `swaggerJsonPath` | `undefined` | Path relative to mount path where OpenAPI schema is served as JSON. When set, Swagger UI loads the schema from this endpoint instead of embedding it directly. | | `authPolicy` | `AuthPolicy.disabled` | Controls authentication for the Swagger UI page itself. | +| `securitySchemes` | `undefined` | OpenAPI Security Schemes | Usage example: @@ -95,6 +96,13 @@ const {registerRoutes} = createOpenApiRegistry({ explorer: true, customCss: '.topbar { display: none; }', }, + securitySchemes: { + myApiKey: { + type: 'apiKey', + in: 'header', + name: 'X-API-Key', + }, + }, }); ``` diff --git a/src/openapi-registry.ts b/src/openapi-registry.ts index 8ebcb93..495db90 100644 --- a/src/openapi-registry.ts +++ b/src/openapi-registry.ts @@ -32,6 +32,8 @@ import {NodeKit} from '@gravity-ui/nodekit'; * @returns An object with methods to register routes, security schemes, and generate the OpenAPI schema */ export function createOpenApiRegistry(config: OpenApiRegistryConfig) { + const initialSecuritySchemes = {...(config.securitySchemes || {})}; + const openApiSchema: OpenApiSchemaObject = { openapi: '3.0.3', info: { @@ -43,7 +45,7 @@ export function createOpenApiRegistry(config: OpenApiRegistryConfig) { paths: {}, components: { schemas: {}, - securitySchemes: {}, + securitySchemes: {...initialSecuritySchemes}, }, }; @@ -272,7 +274,7 @@ export function createOpenApiRegistry(config: OpenApiRegistryConfig) { openApiSchema.paths = {}; if (openApiSchema.components) { openApiSchema.components.schemas = {}; - openApiSchema.components.securitySchemes = {}; + openApiSchema.components.securitySchemes = {...initialSecuritySchemes}; } } diff --git a/src/tests/openapi-registry.test.ts b/src/tests/openapi-registry.test.ts index 81d21a1..02454c7 100644 --- a/src/tests/openapi-registry.test.ts +++ b/src/tests/openapi-registry.test.ts @@ -47,6 +47,13 @@ describe('openapi-registry', () => { {url: 'https://staging.example.com', description: 'Staging'}, ], path: '/docs', + securitySchemes: { + customApiKey: { + type: 'apiKey' as const, + in: 'header' as const, + name: 'X-Custom-Key', + }, + }, }; const {getOpenApiSchema} = createOpenApiRegistry(config); @@ -58,6 +65,13 @@ describe('openapi-registry', () => { expect(schema.info.contact).toEqual(config.contact); expect(schema.info.license).toEqual(config.license); expect(schema.servers).toEqual(config.servers); + expect(schema.components?.securitySchemes).toEqual({ + customApiKey: { + type: 'apiKey', + in: 'header', + name: 'X-Custom-Key', + }, + }); }); it('should create registry with swaggerUi options', () => { @@ -787,9 +801,23 @@ describe('openapi-registry', () => { }); describe('reset', () => { - it('should reset paths and components', () => { - const {registerRoutes, getOpenApiSchema, reset} = createOpenApiRegistry({ - title: 'Test API', + it('should reset paths and components to initial state', () => { + const {registerRoutes, getOpenApiSchema, reset, registerSecurityScheme} = + createOpenApiRegistry({ + title: 'Test API', + securitySchemes: { + initialKey: { + type: 'apiKey', + in: 'header', + name: 'X-Initial-Key', + }, + }, + }); + + registerSecurityScheme('runtimeKey', { + type: 'apiKey', + in: 'header', + name: 'X-Runtime-Key', }); const handler = withContract({ @@ -809,12 +837,31 @@ describe('openapi-registry', () => { expect(schema.paths['/test']).toBeDefined(); + expect(schema.components?.securitySchemes).toEqual({ + initialKey: { + type: 'apiKey', + in: 'header', + name: 'X-Initial-Key', + }, + runtimeKey: { + type: 'apiKey', + in: 'header', + name: 'X-Runtime-Key', + }, + }); + reset(); schema = getOpenApiSchema(); expect(schema.paths).toEqual({}); expect(schema.components?.schemas).toEqual({}); - expect(schema.components?.securitySchemes).toEqual({}); + expect(schema.components?.securitySchemes).toEqual({ + initialKey: { + type: 'apiKey', + in: 'header', + name: 'X-Initial-Key', + }, + }); }); }); diff --git a/src/types.ts b/src/types.ts index 1f5ddf6..e2d343f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -65,6 +65,7 @@ export interface OpenApiRegistryConfig { swaggerUi?: SwaggerUiOptions; swaggerJsonPath?: string; authPolicy?: AuthPolicy; + securitySchemes?: Record; transformOperation?: ( operation: OpenApiOperation, context: {