Spaces:
Sleeping
Sleeping
import { config } from "@configs/config"; | |
/** | |
* Swagger registry class. | |
*/ | |
class SwaggerRegistry { | |
public controllersRegistry = new Map< | |
any, | |
{ | |
routes: { | |
propertyKey: string; | |
path?: string; | |
method?: "get" | "post" | "put" | "patch" | "delete"; | |
request?: any; | |
response?: any; | |
queryParams?: any; | |
description?: string; | |
summary?: string; | |
tags?: string[]; | |
}[]; | |
prefix: string; | |
tags?: string[]; | |
} | |
>(); | |
public schemasRegistry = new Map< | |
any, | |
{ | |
properties: { | |
[key: string]: any; | |
}; | |
propertiesToExclude: string[]; | |
} | |
>(); | |
public initSchemaIfNotExists(schema: any) { | |
if (!this.schemasRegistry.has(schema)) { | |
this.schemasRegistry.set(schema, { | |
properties: {}, | |
propertiesToExclude: [], | |
}); | |
} | |
} | |
public updateSchemaProperty(props: { | |
schema: any; | |
property: string; | |
newName?: string; | |
type: any; | |
}) { | |
this.initSchemaIfNotExists(props.schema); | |
const data = this.schemasRegistry.get(props.schema); | |
data.properties[props.newName || props.property] = { type: props.type }; | |
if (props.newName) { | |
data.propertiesToExclude.push(props.property); | |
} | |
this.schemasRegistry.set(props.schema, data); | |
} | |
public initControllerIfNotExists(controller: any, prefix: string = "") { | |
if (!this.controllersRegistry.has(controller)) { | |
this.controllersRegistry.set(controller, { | |
routes: [], | |
prefix, | |
}); | |
} | |
} | |
public setControllerPrefix(controller: any, prefix: string) { | |
this.initControllerIfNotExists(controller); | |
const data = this.controllersRegistry.get(controller); | |
data.prefix = prefix; | |
this.controllersRegistry.set(controller, data); | |
} | |
public updateRoute( | |
controller: any, | |
params: { | |
propertyKey: string; | |
path?: string; | |
method?: "get" | "post" | "put" | "patch" | "delete"; | |
request?: any; | |
response?: any; | |
queryParams?: any; | |
description?: string; | |
summary?: string; | |
tags?: string[]; | |
} | |
) { | |
this.initControllerIfNotExists(controller); | |
const data = this.controllersRegistry.get(controller); | |
// delete undefined keys | |
Object.keys(params).forEach( | |
(key) => params[key] === undefined && delete params[key] | |
); | |
const route = data.routes.find( | |
(route) => route.propertyKey === params.propertyKey | |
); | |
if (route) { | |
Object.assign(route, params); | |
} else { | |
data.routes.push(params); | |
} | |
this.controllersRegistry.set(controller, data); | |
} | |
public setControllerTags(controller: any, tags: string[]) { | |
this.initControllerIfNotExists(controller); | |
const data = this.controllersRegistry.get(controller); | |
data.tags = tags; | |
this.controllersRegistry.set(controller, data); | |
} | |
public generateSwaggerDocument() { | |
const paths: any = {}; | |
this.controllersRegistry.forEach((value) => { | |
const controllerData = value; | |
controllerData.routes.forEach((route) => { | |
route.path = `/api/v1${controllerData.prefix}${route.path}`; | |
// convert :param to {param} | |
route.path = route.path.replace(/:(\w+)/g, "{$1}"); | |
const params = route.path.match(/{(\w+)}/g); | |
if (!paths[route.path]) { | |
paths[route.path] = {}; | |
} | |
paths[route.path][route.method] = { | |
security: [ | |
{ | |
bearerAuth: [], | |
}, | |
], | |
tags: [...(controllerData.tags || []), ...(route.tags || [])], | |
summary: route.summary, | |
description: route.description, | |
parameters: [ | |
...((params && | |
params.map((param) => { | |
return { | |
name: param.replace(/{|}/g, ""), | |
in: "path", | |
required: true, | |
schema: { | |
type: "string", | |
}, | |
}; | |
})) || | |
[]), | |
...(route.queryParams || []), | |
], | |
responses: { | |
200: { | |
description: "Success", | |
content: { | |
"application/json": { | |
schema: route.response, | |
}, | |
}, | |
}, | |
}, | |
}; | |
if (route.request) { | |
paths[route.path][route.method].requestBody = { | |
content: { | |
"application/json": { | |
schema: route.request, | |
}, | |
}, | |
}; | |
} | |
}); | |
}); | |
const document = { | |
openapi: "3.0.0", | |
info: { | |
title: "Modarb API Documentation", | |
version: "1.0.0", | |
description: "Look! Docs!", | |
}, | |
servers: [ | |
{ | |
url: config.swaggerServer || `${config.host}:${config.port}`, | |
}, | |
], | |
security: [ | |
{ | |
bearerAuth: [], | |
}, | |
], | |
paths, | |
components: { | |
securitySchemes: { | |
bearerAuth: { | |
type: "http", | |
scheme: "bearer", | |
bearerFormat: "JWT", | |
}, | |
}, | |
}, | |
}; | |
//console.log(JSON.stringify(document, null, 2)); | |
return document; | |
} | |
} | |
export const swaggerRegistry = new SwaggerRegistry(); | |