@nestjs/swagger
Version:
Nest - modern, fast, powerful node.js web framework (@swagger)
89 lines (88 loc) • 4.17 kB
JavaScript
import { HttpStatus, RequestMethod } from '@nestjs/common';
import { HTTP_CODE_METADATA, METHOD_METADATA } from '@nestjs/common/constants.js';
import { isEmpty } from '@nestjs/common/utils/shared.utils.js';
import { mapValues, omit } from 'es-toolkit/compat';
import { DECORATORS } from '../constants.js';
import { ApiResponse } from '../decorators/index.js';
import { METADATA_FACTORY_NAME } from '../plugin/plugin-constants.js';
import { GlobalResponsesStorage } from '../storages/global-responses.storage.js';
import { mergeAndUniq } from '../utils/merge-and-uniq.util.js';
export const exploreGlobalApiResponseMetadata = (schemas, responseObjectFactory, metatype, factories) => {
const responses = Reflect.getMetadata(DECORATORS.API_RESPONSE, metatype);
const globalResponses = GlobalResponsesStorage.getAll();
const mappedGlobalResponsesOrUndefined = globalResponses
? mapResponsesToSwaggerResponses(globalResponses, schemas, responseObjectFactory, undefined, factories)
: undefined;
const produces = Reflect.getMetadata(DECORATORS.API_PRODUCES, metatype);
return responses
? {
responses: {
...mappedGlobalResponsesOrUndefined,
...mapResponsesToSwaggerResponses(responses, schemas, responseObjectFactory, produces, factories)
}
}
: mappedGlobalResponsesOrUndefined
? {
responses: mappedGlobalResponsesOrUndefined
}
: undefined;
};
export const exploreApiResponseMetadata = (schemas, responseObjectFactory, factories, instance, prototype, method, metatype) => {
applyMetadataFactory(prototype, instance);
const responses = Reflect.getMetadata(DECORATORS.API_RESPONSE, method);
if (responses) {
const classProduces = Reflect.getMetadata(DECORATORS.API_PRODUCES, metatype ?? prototype?.constructor);
const methodProduces = Reflect.getMetadata(DECORATORS.API_PRODUCES, method);
const produces = mergeAndUniq(classProduces, methodProduces);
return mapResponsesToSwaggerResponses(responses, schemas, responseObjectFactory, produces, factories);
}
const status = getStatusCode(method);
if (status) {
return { [status]: { description: '' } };
}
return undefined;
};
const getStatusCode = (method) => {
const status = Reflect.getMetadata(HTTP_CODE_METADATA, method);
if (status) {
return status;
}
const requestMethod = Reflect.getMetadata(METHOD_METADATA, method);
switch (requestMethod) {
case RequestMethod.POST:
return HttpStatus.CREATED;
default:
return HttpStatus.OK;
}
};
const omitParamType = (param) => omit(param, 'type');
const mapResponsesToSwaggerResponses = (responses, schemas, responseObjectFactory, produces = ['application/json'], factories) => {
produces = isEmpty(produces) ? ['application/json'] : produces;
const openApiResponses = mapValues(responses, (response) => responseObjectFactory.create(response, produces, schemas, factories));
return mapValues(openApiResponses, omitParamType);
};
function applyMetadataFactory(prototype, instance) {
const classPrototype = prototype;
do {
if (!prototype.constructor) {
return;
}
if (!prototype.constructor[METADATA_FACTORY_NAME]) {
continue;
}
const metadata = prototype.constructor[METADATA_FACTORY_NAME]();
const methodKeys = Object.keys(metadata).filter((key) => typeof instance[key] === 'function');
methodKeys.forEach((key) => {
const { summary, deprecated, tags, ...meta } = metadata[key];
if (Object.keys(meta).length === 0) {
return;
}
if (meta.status === undefined) {
meta.status = getStatusCode(instance[key]);
}
ApiResponse(meta, { overrideExisting: false })(classPrototype, key, Object.getOwnPropertyDescriptor(classPrototype, key));
});
} while ((prototype = Reflect.getPrototypeOf(prototype)) &&
prototype !== Object.prototype &&
prototype);
}