fix: pre-fetch URL spec then bundle+dereference to handle self-referencing $ref
This commit is contained in:
@@ -115,8 +115,19 @@ function parseOpenApi3Endpoints(api: OpenApiDoc): { endpoints: ParsedEndpoint[];
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function parseOpenApiDocument(input: string | object): Promise<ParseResult> {
|
export async function parseOpenApiDocument(input: string | object): Promise<ParseResult> {
|
||||||
// Parse and dereference all $refs inline
|
let specInput: string | object = input;
|
||||||
const api = await SwaggerParser.dereference(input as any, {
|
|
||||||
|
// If input is a URL, fetch the content first so that swagger-parser
|
||||||
|
// works on a plain object and doesn't need network access for $ref resolution
|
||||||
|
if (typeof input === 'string' && input.startsWith('http')) {
|
||||||
|
const res = await fetch(input);
|
||||||
|
if (!res.ok) throw new Error(`Failed to fetch spec from URL: ${res.status} ${res.statusText}`);
|
||||||
|
specInput = await res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bundle resolves all $refs into a single document, then dereference inlines them
|
||||||
|
const bundled = await SwaggerParser.bundle(specInput as any) as OpenAPI.Document;
|
||||||
|
const api = await SwaggerParser.dereference(bundled, {
|
||||||
dereference: { circular: 'ignore' },
|
dereference: { circular: 'ignore' },
|
||||||
}) as OpenAPI.Document;
|
}) as OpenAPI.Document;
|
||||||
|
|
||||||
|
|||||||
@@ -31,20 +31,14 @@ export default function ImportDialog({ onClose }: { onClose: () => void }) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError('');
|
setError('');
|
||||||
try {
|
try {
|
||||||
let spec: unknown;
|
let body: Record<string, unknown>;
|
||||||
|
|
||||||
if (mode === 'url') {
|
if (mode === 'url') {
|
||||||
// Fetch from browser (can access local network) instead of letting server fetch
|
body = { specUrl: url };
|
||||||
const res = await fetch(url);
|
|
||||||
if (!res.ok) throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`);
|
|
||||||
const text = await res.text();
|
|
||||||
try { spec = JSON.parse(text); } catch { spec = text; }
|
|
||||||
} else {
|
} else {
|
||||||
try { spec = JSON.parse(fileContent); } catch { spec = fileContent; }
|
try { body = { spec: JSON.parse(fileContent) }; } catch { body = { spec: fileContent }; }
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await apiFetch<ImportResult>('/projects', {
|
const data = await apiFetch<ImportResult>('/projects', {
|
||||||
method: 'POST', body: JSON.stringify({ spec }),
|
method: 'POST', body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
setResult(data);
|
setResult(data);
|
||||||
queryClient.invalidateQueries({ queryKey: ['projects'] });
|
queryClient.invalidateQueries({ queryKey: ['projects'] });
|
||||||
|
|||||||
Reference in New Issue
Block a user