UNPKG

@furystack/rest-service

Version:

Repository implementation for FuryStack

124 lines (116 loc) 3.51 kB
import type { ApiEndpointDefinition, Operation, ParameterObject, SwaggerDocument } from '@furystack/rest' /** * Converts a FuryStack API schema to an OpenAPI 3.1 compatible document * * @param schema - The FuryStack API schema to convert * @returns A SwaggerDocument in OpenAPI 3.1 format */ export const generateSwaggerJsonFromApiSchema = ({ api, title = 'FuryStack API', description = 'API documentation generated from FuryStack API schema', version = '1.0.0', }: { api: Record<string, ApiEndpointDefinition> title?: string description?: string version?: string }): SwaggerDocument => { const swaggerJson: SwaggerDocument = { openapi: '3.1.0', info: { title, version, description, }, jsonSchemaDialect: 'https://spec.openapis.org/oas/3.1/dialect/base', servers: [{ url: '/' }], tags: [], paths: {}, components: { schemas: {}, securitySchemes: { cookieAuth: { type: 'apiKey', in: 'cookie', name: 'session', }, }, }, } for (const [path, definition] of Object.entries(api)) { // Normalize path to OpenAPI format (convert :param to {param}) const normalizedPath = path.replace(/:([^/]+)/g, '{$1}') if (!swaggerJson.paths![normalizedPath]) { swaggerJson.paths![normalizedPath] = {} } // Extract path parameters const pathParams = Array.from(path.matchAll(/:([^/]+)/g), (m) => m[1]) const parameters: ParameterObject[] = pathParams.map((param) => ({ name: param, in: 'path', required: true, description: `Path parameter: ${param}`, schema: { type: 'string' }, })) // Build operation const method = definition.method.toLowerCase() const operation: Operation = { summary: `${definition.method} ${path}`, description: `Endpoint for ${path}`, operationId: `${method}${path.replace(/\//g, '_').replace(/:/g, '').replace(/-/g, '_')}`, security: definition.isAuthenticated ? [{ cookieAuth: [] }] : [], parameters, responses: { '200': { description: 'Successful operation', content: { 'application/json': { schema: definition.schemaName ? { $ref: `#/components/schemas/${definition.schemaName}` } : { type: 'object' }, }, }, }, '401': { description: 'Unauthorized' }, '500': { description: 'Internal server error' }, }, } // Add schema to components if not already there if (definition.schema && definition.schemaName) { swaggerJson.components!.schemas![definition.schemaName] = definition.schema } // Assign the operation to the correct HTTP method property of PathItem const pathItem = swaggerJson.paths![normalizedPath] switch (method) { case 'get': pathItem.get = operation break case 'put': pathItem.put = operation break case 'post': pathItem.post = operation break case 'delete': pathItem.delete = operation break case 'options': pathItem.options = operation break case 'head': pathItem.head = operation break case 'patch': pathItem.patch = operation break case 'trace': pathItem.trace = operation break default: // Ignore unknown methods break } } return swaggerJson }