Skip to content

Instantly share code, notes, and snippets.

@gioragutt
Last active December 8, 2021 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gioragutt/c29b35aaf805f7eb9de270f89f76f843 to your computer and use it in GitHub Desktop.
Save gioragutt/c29b35aaf805f7eb9de270f89f76f843 to your computer and use it in GitHub Desktop.
nestjs swagger helper for extracting inline schemas to the document schemas
/* eslint-disable @typescript-eslint/no-explicit-any */
import { getSchemaPath, OpenAPIObject } from '@nestjs/swagger';
import _set from 'lodash.set';
import _get from 'lodash.get';
function flattenObject(theObject: any): Record<string, any> {
const toReturn: any = {};
for (const objectKey in theObject) {
if (!Object.prototype.hasOwnProperty.call(theObject, objectKey)) {
continue;
}
if (typeof theObject[objectKey] == 'object') {
const flatObject = flattenObject(theObject[objectKey] as any);
for (const x in flatObject) {
if (!Object.prototype.hasOwnProperty.call(flatObject, x)) {
continue;
}
toReturn[objectKey + '.' + x] = flatObject[x];
}
} else {
toReturn[objectKey] = theObject[objectKey];
}
}
return toReturn;
}
/**
* # What is this?
*
* The plugin goes over endpoint definitions, looks for responses that are titles `PaginatedResponseOf(.*)`,
* And moves them to the global schemas section of the document, replacing the response scheme to reference them.
*
* # Why is it needed?
*
* 1. Without that, you don't get an accurate schema definition in the definitions section,
* Which is bad for user experience
* 2. And this is the bad one, openapi-generator-cli with the typescript-fetch template generates broken code,
* Because it does not take the `title` of the inline schema as the name of the schema.
* Example code: `PaginationResponseDTO & objectFromJson(value)` instead of `PaginatedResponseOfMyModelFromJson(value)`
*/
export function extractPaginatedResponsesToDefinitions(document: OpenAPIObject): void {
const flattenedSwagger = flattenObject(document);
const keys = Object.keys(flattenedSwagger);
keys
.filter(k => k.endsWith('schema.title'))
.forEach(key => {
const title = flattenedSwagger[key];
if (!title.startsWith('PaginatedResponseOf')) {
return;
}
const schemaKey = key.replace('.title', '');
const schema = _get(document, schemaKey);
_set(document, schemaKey, {
$ref: getSchemaPath(title),
});
document.components.schemas[title] = schema;
});
}
@gioragutt
Copy link
Author

A workaround was found, so this is here for backup and documentation of hardships of the process

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment