Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/igrek8/nestjs-typed-responses

Allows implementation of polymorphism in OAS and exports nest.js exceptions as swagger schemes
https://github.com/igrek8/nestjs-typed-responses

nestjs openapi openapi3 swagger

Last synced: 2 months ago
JSON representation

Allows implementation of polymorphism in OAS and exports nest.js exceptions as swagger schemes

Awesome Lists containing this project

README

        

# [Handle polymorphic responses](https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism) in Nest.js OpenAPI

Enables OpenAPI v3 polymorphism using `__type` metafield to resolve different exceptions or responses within the same HTTP code response group.

[![NPM](https://badgen.net/npm/v/nestjs-typed-responses)](https://www.npmjs.com/nestjs-typed-responses)
[![Coverage](https://codecov.io/gh/igrek8/nestjs-typed-responses/branch/main/graph/badge.svg)](https://codecov.io/gh/igrek8/nestjs-typed-responses)
![Release](https://badgen.net/github/checks/igrek8/nestjs-typed-responses)
![License](https://badgen.net/github/license/igrek8/nestjs-typed-responses)

## Installation

```bash
npm install --save nestjs-typed-responses

yarn add nestjs-typed-responses
```

## OpenAPI

![Swagger](./media/swagger.png)

## Usage

```ts
import { ConsoleLogger, Controller, HttpCode, HttpStatus, Module, Post, ValidationPipe } from '@nestjs/common';
import { APP_PIPE, NestFactory } from '@nestjs/core';
import {
ApiBadRequestResponse,
ApiExtraModels,
ApiForbiddenResponse,
ApiOkResponse,
ApiProperty,
DocumentBuilder,
refs,
SwaggerModule,
} from '@nestjs/swagger';
import { Expose } from 'class-transformer';
import { IsDateString, IsString } from 'class-validator';
import {
ApiTypeMetafield,
BadRequestException,
ServiceUnavailableException,
TypedDataTransferObject,
TypedResponseModule,
ValidationException,
} from 'nestjs-typed-responses';

class MyResponse implements TypedDataTransferObject {
// ApiTypeMetafield must be defined to specify serializable type
@ApiTypeMetafield('MyResponse')
__type = 'MyResponse';

// It is not required to apply @Expose decorator (per configuration)
@ApiProperty()
@IsString()
data!: string;

constructor(props: Omit) {
Object.assign(this, props);
}
}

class MaintenanceException extends ServiceUnavailableException implements TypedDataTransferObject {
// ApiTypeMetafield must be defined to specify serializable type
@ApiTypeMetafield('MaintenanceException')
override __type = 'MaintenanceException';

// @Expose must be used explicitly in error classes as only such fields will be exposed
@Expose()
@ApiProperty({
example: '2022-12-31T11:00:00.000Z',
description: 'There is a maintenance on the server',
})
@IsDateString()
operationalAt!: Date;
}

@Controller()
@ApiExtraModels(ValidationException, BadRequestException)
class AppController {
@Post()
@HttpCode(HttpStatus.OK)
@ApiOkResponse({ type: MyResponse })
@ApiForbiddenResponse({ type: MaintenanceException })
// Polymorphism https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/
@ApiBadRequestResponse({ schema: { oneOf: refs(ValidationException, BadRequestException) } })
demo(): MyResponse {
return new MyResponse({
data: 'Hello!',
});
}
}

@Module({
providers: [
{
provide: APP_PIPE,
useValue: new ValidationPipe({
exceptionFactory: ValidationException.exceptionFactory,
}),
},
],
imports: [TypedResponseModule],
controllers: [AppController],
})
class AppModule {}

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder().build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('/', app, document);
await app.listen(3000);
}
bootstrap();
```