Skip to content

Commit 3225366

Browse files
committed
improve swagger import
1 parent d0d1294 commit 3225366

3 files changed

Lines changed: 88 additions & 32 deletions

File tree

packages/dashboard/src/app/(layout)/services/import/components/ImportOptions.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ export default function ImportOptions({onImportComplete}: ImportOptionsProps) {
4848
const fileText = await file.text();
4949

5050
const parsedResult = parseSwagger(fileText);
51-
51+
console.log('parsedResult')
52+
console.log(parsedResult)
5253
return parsedResult
5354
} else if (method === "postman" && file) {
5455

packages/dashboard/src/app/(layout)/services/import/parseSwagger.ts

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import {Tables} from "@/utils/supabase/database.types";
22

33
interface SwaggerSchema {
4-
swagger: string;
4+
swagger?: string;
5+
openapi?: string; // Add support for OpenAPI 3.0
56
info: {
67
title: string;
78
description?: string;
89
version: string;
910
};
10-
host: string;
11-
basePath: string;
12-
schemes: string[];
11+
// Swagger 2.0 properties
12+
host?: string;
13+
basePath?: string;
14+
schemes?: string[];
15+
// OpenAPI 3.0 properties
16+
servers?: {
17+
url: string;
18+
description?: string;
19+
variables?: Record<string, any>;
20+
}[];
1321
paths: {
1422
[path: string]: {
1523
[method: string]: {
@@ -19,10 +27,15 @@ interface SwaggerSchema {
1927
operationId: string;
2028
parameters?: any[];
2129
responses: any;
30+
requestBody?: any; // Added for OpenAPI 3.0
2231
}
2332
}
2433
};
25-
securityDefinitions?: Record<string, any>;
34+
securityDefinitions?: Record<string, any>; // Swagger 2.0
35+
components?: { // OpenAPI 3.0
36+
schemas?: Record<string, any>;
37+
securitySchemes?: Record<string, any>;
38+
};
2639
}
2740

2841
export interface ParsedSwaggerResult {
@@ -35,7 +48,6 @@ export interface ParsedSwaggerResult {
3548
*/
3649
export function parseSwagger(swaggerJson: string): ParsedSwaggerResult {
3750
try {
38-
3951
const swagger: SwaggerSchema = JSON.parse(swaggerJson);
4052

4153
// Create the service object
@@ -55,9 +67,19 @@ export function parseSwagger(swaggerJson: string): ParsedSwaggerResult {
5567
* Create a service object based on Swagger info
5668
*/
5769
function createServiceObject(swagger: SwaggerSchema): Tables<'services'> {
58-
// Determine the base URL from host, basePath, and schemes
59-
const scheme = getPreferredScheme(swagger.schemes);
60-
const baseUrl = `${scheme}://${swagger.host}${swagger.basePath}`;
70+
// Determine the base URL based on the specification version
71+
let baseUrl = '';
72+
73+
if (swagger.swagger) {
74+
// Swagger 2.0 format
75+
const scheme = getPreferredScheme(swagger.schemes);
76+
baseUrl = `${scheme}://${swagger.host || ''}${swagger.basePath || ''}`;
77+
} else if (swagger.openapi) {
78+
// OpenAPI 3.0 format
79+
if (swagger.servers && swagger.servers.length > 0) {
80+
baseUrl = swagger.servers[0].url;
81+
}
82+
}
6183

6284
// Determine authentication type
6385
const {authType, authEnabled, authConfig} = determineAuthSettings(swagger);
@@ -102,21 +124,13 @@ function getPreferredScheme(schemes?: string[]): string {
102124
}
103125

104126
/**
105-
* Determine authentication settings from Swagger security definitions
127+
* Determine authentication settings from security definitions
106128
*/
107129
function determineAuthSettings(swagger: SwaggerSchema): {
108130
authType: 'api_key' | 'token' | null;
109131
authEnabled: boolean;
110132
authConfig: any | null;
111133
} {
112-
if (!swagger.securityDefinitions) {
113-
return {
114-
authType: null,
115-
authEnabled: false,
116-
authConfig: null
117-
};
118-
}
119-
120134
// Initialize empty auth config object with the required structure
121135
const authConfig = {
122136
api_key: "",
@@ -126,8 +140,21 @@ function determineAuthSettings(swagger: SwaggerSchema): {
126140
api_key_location: ""
127141
};
128142

143+
// Check for security definitions based on the spec version
144+
const securityDefinitions = swagger.swagger
145+
? swagger.securityDefinitions
146+
: swagger.components?.securitySchemes;
147+
148+
if (!securityDefinitions) {
149+
return {
150+
authType: null,
151+
authEnabled: false,
152+
authConfig: null
153+
};
154+
}
155+
129156
// Check for API Key authentication
130-
const apiKeyDef = Object.entries(swagger.securityDefinitions)
157+
const apiKeyDef = Object.entries(securityDefinitions)
131158
// eslint-disable-next-line @typescript-eslint/no-unused-vars
132159
.find(([_, def]) => def.type === 'apiKey');
133160

@@ -146,7 +173,7 @@ function determineAuthSettings(swagger: SwaggerSchema): {
146173
}
147174

148175
// Check for OAuth or other token-based authentication
149-
const tokenDef = Object.entries(swagger.securityDefinitions)
176+
const tokenDef = Object.entries(securityDefinitions)
150177
// eslint-disable-next-line @typescript-eslint/no-unused-vars
151178
.find(([_, def]) => def.type === 'oauth2' || def.type === 'http');
152179

@@ -163,7 +190,7 @@ function determineAuthSettings(swagger: SwaggerSchema): {
163190
}
164191

165192
// Handle unsupported auth types
166-
const unsupportedAuth = Object.entries(swagger.securityDefinitions)
193+
const unsupportedAuth = Object.entries(securityDefinitions)
167194
// eslint-disable-next-line @typescript-eslint/no-unused-vars
168195
.find(([_, def]) => def.type !== 'apiKey' && def.type !== 'oauth2');
169196

@@ -184,6 +211,9 @@ function determineAuthSettings(swagger: SwaggerSchema): {
184211
function createEndpointsArray(swagger: SwaggerSchema, baseUrl: string): Tables<'endpoints'>[] {
185212
const endpoints: Tables<'endpoints'>[] = [];
186213

214+
// Get component schemas (for OpenAPI 3.0)
215+
const componentSchemas = swagger.openapi ? swagger.components?.schemas : null;
216+
187217
// Process each path and method combination
188218
for (const [path, pathItem] of Object.entries(swagger.paths)) {
189219
for (const [method, operation] of Object.entries(pathItem)) {
@@ -204,6 +234,22 @@ function createEndpointsArray(swagger: SwaggerSchema, baseUrl: string): Tables<'
204234
// Get description from the operation
205235
const description = operation.description || operation.summary || '';
206236

237+
// Create schema object with components references for OpenAPI 3.0
238+
const schema: any = {
239+
parameters: operation.parameters || [],
240+
responses: operation.responses,
241+
};
242+
243+
// Add requestBody for OpenAPI 3.0
244+
if (operation.requestBody) {
245+
schema.requestBody = operation.requestBody;
246+
}
247+
248+
// Add component schemas if available (OpenAPI 3.0)
249+
if (componentSchemas) {
250+
schema.components = { schemas: componentSchemas };
251+
}
252+
207253
// Create endpoint object
208254
const endpoint: Partial<Tables<'endpoints'>> = {
209255
name,
@@ -212,10 +258,7 @@ function createEndpointsArray(swagger: SwaggerSchema, baseUrl: string): Tables<'
212258
regex_path,
213259
description,
214260
source: 'openapi',
215-
schema: {
216-
parameters: operation.parameters || [],
217-
responses: operation.responses,
218-
},
261+
schema,
219262
};
220263

221264
endpoints.push(endpoint as Tables<'endpoints'>);

packages/dashboard/src/utils/generateSwaggerSpec.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Tables } from "@/utils/supabase/database.types";
22
import { env } from "next-runtime-env";
33

4-
//TODO - add accepts & returns, add schema objects
54
export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: Tables<'endpoints'>[], title: string) => {
6-
//eslint-disable-next-line
7-
const paths: any = {}
8-
//eslint-disable-next-line
5+
const paths: any = {};
96
const tags: any[] = [];
107

8+
// For collecting all component schemas from endpoints
9+
const allComponentSchemas: Record<string, any> = {};
10+
1111
// Global API Key Security Scheme
1212
const securitySchemes = {
1313
api_key: {
@@ -30,7 +30,6 @@ export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: T
3030
const method = endpoint.method.toLowerCase();
3131

3232
// Parse the schema JSON if it exists
33-
//eslint-disable-next-line
3433
let endpointSchema: any = {};
3534
let hasCustomSchema = false;
3635

@@ -41,6 +40,12 @@ export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: T
4140
? JSON.parse(endpoint.schema)
4241
: endpoint.schema;
4342
hasCustomSchema = true;
43+
44+
// Extract component schemas if available
45+
if (endpointSchema.components && endpointSchema.components.schemas) {
46+
// Merge with all component schemas
47+
Object.assign(allComponentSchemas, endpointSchema.components.schemas);
48+
}
4449
} catch (error) {
4550
console.error(`Failed to parse schema for endpoint ${endpoint.name}:`, error);
4651
}
@@ -91,6 +96,7 @@ export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: T
9196
paths[fullPath] = paths[fullPath] || {};
9297
paths[fullPath][method] = {
9398
tags: [service.name],
99+
summary: endpoint.description || `${method.toUpperCase()} ${endpoint.name}`,
94100
description: endpoint.description || `Will call ${endpoint.full_url}`,
95101
parameters,
96102
requestBody,
@@ -99,6 +105,12 @@ export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: T
99105
});
100106
});
101107

108+
// Build the complete OpenAPI specification
109+
const components = {
110+
schemas: Object.keys(allComponentSchemas).length > 0 ? allComponentSchemas : undefined,
111+
securitySchemes
112+
};
113+
102114
return {
103115
openapi: "3.0.0",
104116
info: {
@@ -109,7 +121,7 @@ export const generateSwaggerSpec = (services: Tables<'services'>[], endpoints: T
109121
servers: [{ url: `${env('NEXT_PUBLIC_BACKEND_URL')}/api` }],
110122
paths,
111123
tags,
112-
components: { securitySchemes },
124+
components,
113125
security: [{ api_key: [] }] // Applies to all operations
114126
};
115127
};

0 commit comments

Comments
 (0)