Swagger: [next] Major release notes & plans

Created on 18 Feb 2019  路  29Comments  路  Source: nestjs/swagger

The @nestjs/swagger is one of the most widely used @nestjs packages under the @nestjs organization. So far it works pretty great - we have a declarative way to easily generate OpenAPI specification using decorators placed near to our DTOs/routes, we cover 3/4 potential use-cases providing a quite simple API to interact with.

However, the current model of this library doesn't fit the requirements which we should set ourselves in order to ensure that we provide the best quality for developers. Let me list a number of them.

  • massive redundancy (lots of decorators that shouldn't be required)
  • lack of consistency (if we want to change our property to an optional one, we very likely have to add @IsOptional() - for the validation purposes, change the decorator to @ApiModelPropertyOptional() and add a question ? mark by the end of the property name)
  • no generics support
  • no interfaces support
  • no auto-response schemas generation
  • lack of flexibility (hard to add custom rules/decorators/interpreters)
  • no circular-dependencies support

The main reason for all of these outlined issues is weak TypeScript reflection capability. Hence, the library itself will be very likely rewritten and will use TypeScript AST to support all these amazing features out-of-the-box.

I have created this issue in order to share plans with you as well as encourage you to share your personal experiences with this library - if there is something else that was very troublesome/unsupported so far, please, let me know here - we can work on the design specification together.

discussion

Most helpful comment

+1 for the support for OpenAPI 3.0, great work on nestjs in general BTW =).

All 29 comments

Is OpenAPI 3.0 taken into consideration? And also, an abstraction for controllers coverage/approach with Swagger enabled would be awesome. Right now, @Apixxx decorators make it quite hard to implement a BaseController (for lack of better name). ApiUseTags and then the responses types (as you stated, no generics support)

The main reason for all of these outlined issues is weak TypeScript reflection capability. Hence, the library itself will be very likely rewritten and will use TypeScript AST to support all these amazing features out-of-the-box.

Just wondering: will it require a pre-compilation step (or running by a CLI like the yoga2)?
Or you plan to generate the definitions files on the fly like a graphql definition classes in the graphql module? 馃

@19majkel94
I'd like to add 2 possible ways: (1) pre-compilation step (very likely exposed as a plugin to the official CLI as well) (2) generate metadata on the fly and very likely store metadata in a separate file.

Thanks for the update 馃檹, I really thought this module was dying.

I would like to see the following supported in the next version:

  1. multipart-formdata file upload support with additional parameters.

  2. OpenAPI 3 Specs.

The main reason for all of these outlined issues is weak TypeScript reflection capability. Hence, the library itself will be very likely rewritten and will use TypeScript AST to support all these amazing features out-of-the-box.

TypeORM seems to do pretty well at extracting basic type data from TypeScript. And seems to use reflect-metadata to add metadata for columns.

Instead of a pre-compile step or metadata file, what if we tried using the same kind of technique as TypeORM?

For example we could wrap class-validator as @nestjs/class-validator (or @nestjs/validator?) and provide variants that also apply decorator metadata. e.g. The IsOptional from the nestjs class-validator wrapper would apply the class-validator's IsOptional as well as decorating the metadata with an isOptional metadata value. Then the swagger generator would be able to read that metadata and mark the property as optional within the model.

This may be better than pure-typescript, because it would be possible for the @IsEmail() decorator to apply a format: 'email' metadata that would be passed along to Swagger. Which is not something that would be available based on types.

@dantman typeorm uses the same technique as @nestjs/swagger is using right now. It's still very limited (and doesn't allow to solve either of the outlined problems).

+1 for the support for OpenAPI 3.0, great work on nestjs in general BTW =).

@kamilmysliwiec Do you have a projection of how long the rewrite's going to take? Sorry I'm getting too excited I had to ask

@kamilmysliwiec Check out the work at tsoa; it does use the TypeScript compiler API to generate routes and a swagger spec from TypeScript code. I imagine a lot of the code you need for this project has already been implemented there in some form. If nothing else, it may give you a rough idea of the work and scope involved.

@kamilmysliwiec
https://github.com/thiagobustamante/typescript-rest-swagger
It's good to recognize ts types, same way like tsoa;

https://github.com/vellengs/nest-swagger
I made a basic works version from typescript-rest-swagger

My biggest wish for the update would be:

  • OpenAPI 3.0
  • deeply nested Query params (e.g., ?page[size]=100&page[number]=5 ). This would be available in OA3

Thank you so much for your hard work!

For now we have been using class-validator-jsonschema to generate the swagger doc of our body and parameters using class-validator annotations.

Having both the documentation and validation in sync is pretty neat.

I was the original feature requester :)

This was the hack I came up with

```import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { getValidator } from '_/main';
import { ClassType } from 'class-transformer/ClassTransformer';

@Injectable()
export class SwaggerValidationPipe implements PipeTransform {
constructor(private readonly type: ClassType) { }

public transform(value: any, metadata: ArgumentMetadata) {
    const validator = getValidator();
    const swaggerDefinitionName = '#/definitions/' + this.type.name;
    if ( validator.validate(swaggerDefinitionName, value) ) {
        return value;
    }
    throw new BadRequestException(validator.errors, 'INVALID_INPUT');
}

}


import { FastifyAdapter, NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { ApiModule } from '_/api/api.module';
import { getMd } from '_/docs';
import Ajv from 'ajv';
import * as fs from 'fs';
import * as path from 'path';
import { ApplicationModule } from './app.module';

let validator: Ajv.Ajv;

export function getValidator(): Ajv.Ajv {
return validator;
}

async function bootstrap() {
const app = await NestFactory.create(ApplicationModule, new FastifyAdapter());

const description = getMd('description');

const options = new DocumentBuilder()
.setTitle('XXXX')
.setHost('XXXX')
.setSchemes('https')
.setDescription(description)
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document, {});
const ajv = new Ajv({allErrors: true});
ajv.addSchema(document);
validator = ajv;
await app.listen(3000, '0.0.0.0');
}
bootstrap();
```

Any update on the rewrite progress?

Any progress on generics support?

+1 for Open API 3.0 because it has a much better security description (For example explicit Bearer Auth instead of the "API Key header workaround".)

We are investigating Typescript and nestjs as a tech stack for our node services and open api 3 is a requirement. It would be great to get an update. any update :)

yeah, a big plus here for this ... I was wondering why my parameters were being marked as "any" ;)

@dantman

The main reason for all of these outlined issues is weak TypeScript reflection capability. Hence, the library itself will be very likely rewritten and will use TypeScript AST to support all these amazing features out-of-the-box.

TypeORM seems to do pretty well at extracting basic type data from TypeScript. And seems to use reflect-metadata to add metadata for columns.

Instead of a pre-compile step or metadata file, what if we tried using the same kind of technique as TypeORM?

For example we could wrap class-validator as @nestjs/class-validator (or @nestjs/validator?) and provide variants that also apply decorator metadata. e.g. The IsOptional from the nestjs class-validator wrapper would apply the class-validator's IsOptional as well as decorating the metadata with an isOptional metadata value. Then the swagger generator would be able to read that metadata and mark the property as optional within the model.

This may be better than pure-typescript, because it would be possible for the @IsEmail() decorator to apply a format: 'email' metadata that would be passed along to Swagger. Which is not something that would be available based on types.

Today I also thought about this option and found your post :)
But, the most important thing for me is to support the validation groups in the swagger.
Otherwise, too much duplicate code is obtained.

Any news on this? It doesn't appear in the milestones for 7.0.0, can we hope to have this in the near future?

See more here https://github.com/nestjs/swagger/pull/355. I'd love to know your thoughts.

PR has been merged, next version has been published. More information soon.
Migration steps (if you want to try it now): https://github.com/nestjs/swagger/pull/355#issuecomment-547925879

To install run npm i @nestjs/swagger@next. Note: remember to update @nestjs/common, @nestjs/core and typescript as well to ensure that you're using the latest versions.

PR has been merged, next version has been published. More information soon.
Migration steps (if you want to try it now): #355 (comment)

To install run npm i @nestjs/swagger@next. Note: remember to update @nestjs/common, @nestjs/core and typescript as well to ensure that you're using the latest versions.

swagger next cause nestjsx to break because of the abscence of ApiModelProperty

/home/hugo/Documents/programming/wild-api/node_modules/@nestjsx/crud/lib/crud/validation.helper.js:23
            ApiModelProperty(options)(target, propertyKey);

package.json

    "@nestjs/common": "^6.9.0",
    "@nestjs/core": "^6.9.0",
    "@nestjs/jwt": "^6.1.1",
    "@nestjs/passport": "^6.1.0",
    "@nestjs/platform-express": "^6.9.0",
    "@nestjs/swagger": "^4.0.0-next.3",
    "@nestjs/typeorm": "^6.2.0",
    "@nestjsx/crud": "^4.2.0",
    "@nestjsx/crud-typeorm": "^4.2.0",

Edit

Excuse me: Issue already created

@hugoblanc I鈥檇 suggest creating an issue over at nestjsx/crud repository

Dear @hugoblanc , i think, this is (at least for now) perfectly fine, as the new major release for this package (@nestjs/swagger) is not officially released. Furthermore, some decorators may change for the final release..

In this context, the @nestjsx/crud package must adapt, if the @nestjs/swagger package is finally released.. Please note, that these packages are maintained by 2 different organizations!

@kamilmysliwiec Check out the work at tsoa; it does use the TypeScript compiler API to generate routes and a swagger spec from TypeScript code.

I have created this demo repo of nestjs with tsoa integration. It required a slight changes in tsoa in order to support colon path params.

It does support interfaces and it auto generating response types based on function return type.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dennisameling picture dennisameling  路  4Comments

cdiaz picture cdiaz  路  4Comments

kalaivanan-muthusamy picture kalaivanan-muthusamy  路  4Comments

djedlajn picture djedlajn  路  4Comments

KatSick picture KatSick  路  3Comments