UNPKG

burger-api

Version:

<p align="center"> <img src="https://github.com/user-attachments/assets/0d9b376e-1d89-479a-aa7f-e7ee3c6b2342" alt="BurgerAPI logo"/> </p>

128 lines (127 loc) 5.34 kB
import { zodToJsonSchema } from 'zod-to-json-schema'; /** * Builds an array of OpenAPI 3.0 parameters based on the Zod schema. * For each property in the Zod schema, an OpenAPI parameter is constructed * with the same name and required flag. The schema of the parameter is set * to a string type. * @param zodSchema - The Zod schema to construct parameters from. * @param location - The location of the parameter. Must be either "path" or "query". * @returns An array of OpenAPI 3.0 parameter objects. */ function buildParameters(zodSchema, location) { const parameters = []; if (zodSchema && zodSchema._def && typeof zodSchema._def.shape === 'function') { // Get the shape of the Zod schema const shape = zodSchema._def.shape(); for (const key in shape) { // Get the definition of the field const fieldDef = shape[key]; // Determine if the field is optional const isOptional = fieldDef._def.typeName === 'ZodOptional'; parameters.push({ // Set the name of the parameter name: key, // Type of the parameter path or query in: location, // Set the required flag required: !isOptional, // Set the schema type schema: { type: 'string' }, // Description of the parameter description: `${location} parameter ${key}`, }); } } return parameters; } /** * Builds a request body object for OpenAPI based on a Zod schema. * Converts the Zod schema into JSON schema and constructs an OpenAPI * requestBody object with content type "application/json". * @param zodSchema - The Zod schema to convert into JSON schema. * @returns An OpenAPI requestBody object, or undefined if no schema is provided. */ function buildRequestBody(zodSchema) { if (!zodSchema) return undefined; const jsonSchema = zodToJsonSchema(zodSchema); return { content: { 'application/json': { schema: jsonSchema, }, }, description: 'Request body', required: true, }; } /** * Converts a route path from colon-based dynamic segments to OpenAPI's curly brace syntax. * * @param routePath The original route path with colon-based dynamic segments (e.g., "/user/:id"). * @returns The converted route path with curly brace syntax (e.g., "/user/{id}"). */ function convertPathForOpenAPI(routePath) { // Replace occurrences of :param with {param} return routePath.replace(/:([a-zA-Z0-9_]+)/g, '{$1}'); } export function generateOpenAPIDocument(apiRoutes, options) { const openapiDoc = { openapi: '3.0.0', info: { title: options.title || 'Burger API', description: options.description || 'Burger API documentation', version: options.version || '1.0.0', }, paths: {}, }; // Iterate over each route for (const route of apiRoutes) { // Convert colon-based dynamic segments to OpenAPI's {param} syntax const openApiPath = convertPathForOpenAPI(route.path); // Initialize path object if necessary openapiDoc.paths[openApiPath] = openapiDoc.paths[openApiPath] || {}; // For each HTTP method in the route, add an OpenAPI operation. for (const method in route.handlers) { // Convert HTTP method to lowercase const lowerMethod = method.toLowerCase(); // Use provided openapi metadata if available; else, fallback to auto-generated values. const methodMeta = route.openapi?.[lowerMethod] || {}; // Generate an operationId: e.g., "get_api_product" const operationId = methodMeta.operationId || `${lowerMethod}_${route.path.replace(/[\/:]/g, '_')}`; // Build parameters for both path and query from the schema. let parameters = []; if (route.schema && route.schema[lowerMethod]) { const schemaDef = route.schema[lowerMethod]; parameters = [ ...buildParameters(schemaDef.params, 'path'), ...buildParameters(schemaDef.query, 'query'), ]; } // Build requestBody if a body schema exists. let requestBody = undefined; if (route.schema && route.schema[lowerMethod]?.body) { requestBody = buildRequestBody(route.schema[lowerMethod].body); } openapiDoc.paths[openApiPath][lowerMethod] = { operationId, summary: methodMeta.summary || `Summary for ${method} ${route.path}`, description: methodMeta.description || '', tags: methodMeta.tags || [], deprecated: methodMeta.deprecated || false, parameters: parameters, requestBody: requestBody, responses: methodMeta.responses || { '200': { description: 'Successful response', }, }, externalDocs: methodMeta.externalDocs || undefined, }; } } return openapiDoc; }