mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-22 01:36:29 -05:00
feat: create openapi decorator
This decorator gets a list of http codes and possible descriptions and adds all necessary decorator internally to the method or the class. This will prevent long OpenApi annotations and keep the controllers shorter. Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
c6bb8f62e8
commit
a283002a34
2 changed files with 156 additions and 1 deletions
|
@ -1,9 +1,14 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export const okDescription = 'This request was successful';
|
||||
export const createdDescription =
|
||||
'The requested resource was successfully created';
|
||||
export const noContentDescription =
|
||||
'The requested resource was successfully deleted';
|
||||
export const badRequestDescription =
|
||||
"The request is malformed and can't be processed";
|
||||
export const unauthorizedDescription =
|
||||
|
|
150
src/api/utils/openapi.decorator.ts
Normal file
150
src/api/utils/openapi.decorator.ts
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { applyDecorators, Header, HttpCode } from '@nestjs/common';
|
||||
import {
|
||||
ApiBadRequestResponse,
|
||||
ApiConflictResponse,
|
||||
ApiCreatedResponse,
|
||||
ApiInternalServerErrorResponse,
|
||||
ApiNoContentResponse,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiProduces,
|
||||
ApiUnauthorizedResponse,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import { BaseDto } from '../../utils/base.dto.';
|
||||
import {
|
||||
badRequestDescription,
|
||||
conflictDescription,
|
||||
createdDescription,
|
||||
internalServerErrorDescription,
|
||||
noContentDescription,
|
||||
notFoundDescription,
|
||||
okDescription,
|
||||
unauthorizedDescription,
|
||||
} from './descriptions';
|
||||
|
||||
export type HttpStatusCodes =
|
||||
| 200
|
||||
| 201
|
||||
| 204
|
||||
| 400
|
||||
| 401
|
||||
| 403
|
||||
| 404
|
||||
| 409
|
||||
| 500;
|
||||
|
||||
export interface HttpStatusCodeWithExtraInformation {
|
||||
code: HttpStatusCodes;
|
||||
description?: string;
|
||||
isArray?: boolean;
|
||||
dto?: BaseDto;
|
||||
mimeType?: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention,func-style
|
||||
export const OpenApi = (
|
||||
...httpStatusCodesMaybeWithExtraInformation: (
|
||||
| HttpStatusCodes
|
||||
| HttpStatusCodeWithExtraInformation
|
||||
)[]
|
||||
): // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
(<TFunction extends Function, Y>(
|
||||
target: object | TFunction,
|
||||
propertyKey?: string | symbol,
|
||||
descriptor?: TypedPropertyDescriptor<Y>,
|
||||
) => void) => {
|
||||
const decoratorsToApply: (MethodDecorator | ClassDecorator)[] = [];
|
||||
for (const entry of httpStatusCodesMaybeWithExtraInformation) {
|
||||
let code: HttpStatusCodes = 200;
|
||||
let description: string | undefined = undefined;
|
||||
let isArray: boolean | undefined = undefined;
|
||||
let dto: BaseDto | undefined = undefined;
|
||||
if (typeof entry == 'number') {
|
||||
code = entry;
|
||||
} else {
|
||||
// We've got a HttpStatusCodeWithExtraInformation
|
||||
code = entry.code;
|
||||
description = entry.description;
|
||||
isArray = entry.isArray;
|
||||
dto = entry.dto;
|
||||
if (entry.mimeType) {
|
||||
decoratorsToApply.push(
|
||||
ApiProduces(entry.mimeType),
|
||||
Header('Content-Type', entry.mimeType),
|
||||
);
|
||||
}
|
||||
}
|
||||
switch (code) {
|
||||
case 200:
|
||||
decoratorsToApply.push(
|
||||
ApiOkResponse({
|
||||
description: description ?? okDescription,
|
||||
isArray: isArray,
|
||||
type: () => dto,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 201:
|
||||
decoratorsToApply.push(
|
||||
ApiCreatedResponse({
|
||||
description: description ?? createdDescription,
|
||||
isArray: isArray,
|
||||
type: () => dto,
|
||||
}),
|
||||
HttpCode(201),
|
||||
);
|
||||
break;
|
||||
case 204:
|
||||
decoratorsToApply.push(
|
||||
ApiNoContentResponse({
|
||||
description: description ?? noContentDescription,
|
||||
}),
|
||||
HttpCode(204),
|
||||
);
|
||||
break;
|
||||
case 400:
|
||||
decoratorsToApply.push(
|
||||
ApiBadRequestResponse({
|
||||
description: description ?? badRequestDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 401:
|
||||
decoratorsToApply.push(
|
||||
ApiUnauthorizedResponse({
|
||||
description: description ?? unauthorizedDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 404:
|
||||
decoratorsToApply.push(
|
||||
ApiNotFoundResponse({
|
||||
description: description ?? notFoundDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 409:
|
||||
decoratorsToApply.push(
|
||||
ApiConflictResponse({
|
||||
description: description ?? conflictDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 500:
|
||||
decoratorsToApply.push(
|
||||
ApiInternalServerErrorResponse({
|
||||
description: internalServerErrorDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return applyDecorators(...decoratorsToApply);
|
||||
};
|
Loading…
Reference in a new issue