feat: add project CRUD, OpenAPI import/parsing, module and endpoint management routes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
108
packages/server/src/services/openapi-parser.ts
Normal file
108
packages/server/src/services/openapi-parser.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import SwaggerParser from '@apidevtools/swagger-parser';
|
||||
import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
|
||||
|
||||
type OpenApiDoc = OpenAPIV3.Document | OpenAPIV3_1.Document;
|
||||
|
||||
export type ParsedModule = {
|
||||
name: string;
|
||||
description: string | null;
|
||||
source: 'tag' | 'path_prefix';
|
||||
};
|
||||
|
||||
export type ParsedEndpoint = {
|
||||
method: string;
|
||||
path: string;
|
||||
summary: string | null;
|
||||
description: string | null;
|
||||
operationId: string | null;
|
||||
parameters: unknown[];
|
||||
requestBody: unknown | null;
|
||||
responses: Record<string, unknown>;
|
||||
tags: string[];
|
||||
deprecated: boolean;
|
||||
moduleName: string;
|
||||
};
|
||||
|
||||
export type ParseResult = {
|
||||
name: string;
|
||||
description: string | null;
|
||||
version: string;
|
||||
openApiVersion: string;
|
||||
baseUrl: string | null;
|
||||
spec: unknown;
|
||||
modules: ParsedModule[];
|
||||
endpoints: ParsedEndpoint[];
|
||||
};
|
||||
|
||||
export async function parseOpenApiDocument(input: string | object): Promise<ParseResult> {
|
||||
const rawApi = await SwaggerParser.validate(input as any);
|
||||
const api = await SwaggerParser.dereference(rawApi as any) as OpenApiDoc;
|
||||
|
||||
const openApiVersion = 'openapi' in api ? api.openapi : 'unknown';
|
||||
const name = api.info.title;
|
||||
const description = api.info.description || null;
|
||||
const version = api.info.version;
|
||||
const baseUrl = api.servers?.[0]?.url || null;
|
||||
|
||||
const tagMap = new Map<string, string | null>();
|
||||
if (api.tags) {
|
||||
for (const tag of api.tags) {
|
||||
tagMap.set(tag.name, tag.description || null);
|
||||
}
|
||||
}
|
||||
|
||||
const endpoints: ParsedEndpoint[] = [];
|
||||
const usedTags = new Set<string>();
|
||||
|
||||
const paths = api.paths || {};
|
||||
for (const [pathStr, pathItem] of Object.entries(paths)) {
|
||||
if (!pathItem) continue;
|
||||
const methods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as const;
|
||||
for (const method of methods) {
|
||||
const operation = (pathItem as Record<string, unknown>)[method] as OpenAPIV3.OperationObject | undefined;
|
||||
if (!operation) continue;
|
||||
|
||||
const endpointTags = operation.tags || [];
|
||||
for (const tag of endpointTags) {
|
||||
usedTags.add(tag);
|
||||
if (!tagMap.has(tag)) tagMap.set(tag, null);
|
||||
}
|
||||
|
||||
const prefix = pathStr.split('/').filter(Boolean)[0] || 'default';
|
||||
const moduleName = endpointTags[0] || prefix;
|
||||
|
||||
endpoints.push({
|
||||
method: method.toUpperCase(),
|
||||
path: pathStr,
|
||||
summary: operation.summary || null,
|
||||
description: operation.description || null,
|
||||
operationId: operation.operationId || null,
|
||||
parameters: (operation.parameters || []) as unknown[],
|
||||
requestBody: operation.requestBody || null,
|
||||
responses: (operation.responses || {}) as Record<string, unknown>,
|
||||
tags: endpointTags,
|
||||
deprecated: operation.deprecated || false,
|
||||
moduleName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const modules: ParsedModule[] = [];
|
||||
const moduleNames = new Set<string>();
|
||||
|
||||
for (const [tagName, tagDesc] of tagMap) {
|
||||
if (usedTags.has(tagName)) {
|
||||
modules.push({ name: tagName, description: tagDesc, source: 'tag' });
|
||||
moduleNames.add(tagName);
|
||||
}
|
||||
}
|
||||
|
||||
for (const endpoint of endpoints) {
|
||||
if (endpoint.tags.length === 0 && !moduleNames.has(endpoint.moduleName)) {
|
||||
modules.push({ name: endpoint.moduleName, description: null, source: 'path_prefix' });
|
||||
moduleNames.add(endpoint.moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
return { name, description, version, openApiVersion, baseUrl, spec: api, modules, endpoints };
|
||||
}
|
||||
Reference in New Issue
Block a user