nestjs / swagger

OpenAPI (Swagger) module for Nest framework (node.js) :earth_americas:

Home Page:https://nestjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add service to provide granular control over generated resources (like guards)

davidschuette opened this issue · comments

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

I want to integrate swagger files more tightly in my application. One case is to use custom authentication (guards) to restrict access to the generated resources. This would be possible with a dedicated SwaggerService. This service would provide access to all resources (like html file, openapi spec), but can be used more granular.

Example:

@Controller()
export class SomeController {
  constructor(private readonly swaggerService: SwaggerService) {}

  @Get()
  @UseGuards(CustomGuard)
  getHtmlFile() {
    return this.swaggerService.getHtml();
  }

 ....
}

Describe the solution you'd like

Create an injectable service like SwaggerService that can be used to get a readable stream / buffer of each generated resources by the swagger module.
Provide an option to disable automatic registration of routes for swagger resources when instantiating the SwaggerModule.

Maybe more features I did not think of.

Drawbacks:

  • increased complexity

Teachability, documentation, adoption, migration strategy

No response

What is the motivation / use case for changing the behavior?

  • Use existing authentication & authorization instead of using something like express-basic-auth (as discussed here #244)
  • Process files further before exposing them to an endpoint

After you've create the document with SwaggerModule.createDocument() it can be consumed like any other OpenAPI spec document. The elegance of SwaggerModule.setup() is it configures the static asset server and creates the endpoints for you. The downside is that they are public endpoints; not sure if you can directly pass a spec object to the swagger-ui, the examples show loading it from a url.

I find ReDoc easier to navigate and customize, it's also dead simple to serve, pull it from their CDN and pass in the stringified spec document.

Quick POC to replicate SwaggerModule.setup(), from here it's fairly simple to move this to a service.

/** The typical swagger stuff here... */

const html = `<!DOCTYPE html>
<html>
  <head>
    <title>[[title]]</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet" />
    <style>
      body {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="redoc-container"></div>
    <script nonce='' src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"> </script>
    <script>
    Redoc.init(
      [[openApiSpec]],
      {},
      document.getElementById("redoc-container")
    );
    </script>
  </body>
</html>`;

app.use('/open-api', (request: Request, response: Response) => {
  response.type('html');
  response.send(
    html.replace('[[title]]', 'OpenApi').replace('[[openApiSpec]]', JSON.stringify(document)),
  );
});