Swagger: Serverless issue

Created on 5 Mar 2019  路  13Comments  路  Source: nestjs/swagger

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior


Swagger endpoint is not found.

Expected behavior


Html response generated by swagger-ui.

Minimal reproduction of the problem with instructions


Here is an example I use in my project.

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


I'd like to generate swagger documents based on my modules and endpoints, but I cannot.

Environment


"@nestjs/common": "^5.4.0",
"@nestjs/core": "^5.4.0",
"@nestjs/swagger": "^2.5.1",
"aws-serverless-express": "^3.3.5",
"express": "^4.16.4",


For Tooling issues:
- Node version: 8.10  
- Platform: Mac 


Others:
I run my environment with serverless and serverless-offline plugin

Most helpful comment

I had the same problem before with typeorm. My solution was to manually listed entities in the configuration file. So I have two kind of settings.

``export const typeOrmConfig: TypeOrmModuleOptions = { entities: [${__dirname}/../*/.entity{.ts,.js}`],
...typeOrmConfigGeneral,
};

export const typeOrmConfigServerless: TypeOrmModuleOptions = {
entities: [
Category,
Comment,
Discussion,
],
...typeOrmConfigGeneral,
};
`` I choose the configuration based on someenv`.

Do you use typeorm?

All 13 comments

@csakbalint I just ran into this the other day. The problem is that given a swagger path of swagger, swagger-ui-express serves its html file from /swagger/ and will redirect if the request path is /swagger. Unfortunately API Gateway strips the trailing slash from the request path so you have to add it back with the block below.

if (event.path === '/swagger') {
  event.path = '/swagger/';
}

This cannot be done as a middleware as req.path from express is a getter and will throw an error if you try to overwrite it.

I have the similar problem. Swagger documentation doesn't work on AWS lambda using serverless framework. It works testing it locally (sls offline start).

What is very strange, that only one file .js and doesn't have 404. Others does. I have no idea why.

Swagger API documentation:
https://js6bdk1qg3.execute-api.eu-west-2.amazonaws.com/master/api

404:
https://js6bdk1qg3.execute-api.eu-west-2.amazonaws.com/master/swagger-ui-bundle.js

200:
https://js6bdk1qg3.execute-api.eu-west-2.amazonaws.com/master/swagger-ui-init.js

My part of configuration:

  if (event.path === '/api') {
    event.path = '/api/';
  }

event.path = event.path.includes('swagger-ui') ? `/api${event.path}` : event.path;
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

export default (app, isServerless = false): void => {
  const serverUrl = isServerless ? '/dev' : '/';

  const options = new DocumentBuilder()
    .setTitle(process.env.APP_NAME)
    .setDescription(process.env.APP_DESC)
    .setVersion('1.0')
    .addServer(serverUrl)
    .addBearerAuth()
    .build();

  const document = SwaggerModule.createDocument(app, options);

  SwaggerModule.setup('api', app, document);
};

@jtmthf @csakbalint would you have any idea?

Hi @plorencrstit , I am trying to use swagger with serverless and lambda functions.
Can you explain how did you configure it ?

Hi @NastyZ98,
what problem do you have?

Using TS and serverless-plugin-optimize plugin I needed to add to my serverless.yml configuration:

custom:
  optimize:
    external: ['swagger-ui-dist']

in lambda.ts: [my handler]

export const handler: Handler = async (event: any, context: Context) => {
  if (event.path === '/api') {
    event.path = '/api/';
  }
  event.path = event.path.includes('swagger-ui') ? `/api${event.path}` : event.path;

  cachedServer = await bootstrapServer();

  return proxy(cachedServer, event, context, 'PROMISE').promise;
};

@plorencrstit hi, thank you for your reply,
I am trying to make swagger working on my aws lambda but it result of a 404 with sls offline and of an error 500 when I deploy on aws.

I also added serverless-plugin-optimize and edited my serverless.yml but it looks like that serverless-plugin-optimize broke something when I call: myawsurl/dev/api

Capture d鈥檈虂cran 2020-04-22 a虁 00 59 17

Here is my lambda.ts

const binaryMimeTypes: string[] = [];

let cachedServer: Server;

process.on('unhandledRejection', reason => {
  console.error(reason);
});

process.on('uncaughtException', reason => {
  console.error(reason);
});

function setupSwagger(app: INestApplication) {
  const options = new DocumentBuilder()
    .setTitle('Tyffis API')
    .setDescription('Tyffis REST API documentation')
    .setVersion('1.0.0')
    .addTag('tyffis')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);
}

async function bootstrapServer(): Promise<Server> {
  if (!cachedServer) {
    try {
      const expressApp = express();
      const adapter = new ExpressAdapter(expressApp);
      const nestApp = await NestFactory.create(AppModule, adapter);
      nestApp.use(eventContext());
      await nestApp.init();
      setupSwagger(nestApp);
      cachedServer = createServer(expressApp, undefined, binaryMimeTypes);
    } catch (error) {
      return Promise.reject(error);
    }
  }
  return Promise.resolve(cachedServer);
}

export const handler: Handler = async (event: any, context: Context) => {
  if (event.path === '/api') {
    event.path = '/api/';
  }
  event.path = event.path.includes('swagger-ui')
    ? `/api${event.path}`
    : event.path;

  cachedServer = await bootstrapServer();
  return proxy(cachedServer, event, context, 'PROMISE').promise;
};

I had the same problem before with typeorm. My solution was to manually listed entities in the configuration file. So I have two kind of settings.

``export const typeOrmConfig: TypeOrmModuleOptions = { entities: [${__dirname}/../*/.entity{.ts,.js}`],
...typeOrmConfigGeneral,
};

export const typeOrmConfigServerless: TypeOrmModuleOptions = {
entities: [
Category,
Comment,
Discussion,
],
...typeOrmConfigGeneral,
};
`` I choose the configuration based on someenv`.

Do you use typeorm?

Yes I use typeorm, your solution have fixed my problem concerning the entity :) ! But my swagger documentation still don't work..

Capture d鈥檈虂cran 2020-04-22 a虁 10 46 53

Here is my serverless.yml

functions:
  index:
    handler: src/lambda.handler
    events:
      - http:
          cors: true
          path: '/{proxy+}'
          method: any

Did I miss something in my lambda.tsupper ?

Show the entire serverless.yml, please.

Here it is:

service: tyffis-backend-test

provider:
  name: aws
  runtime: nodejs12.x
  region: us-east-1
  stage: dev
  role: LambdaRole
  memorySize: 512
  vpc:
    securityGroupIds:
      - sg
    subnetIds:
      - ids
  environment:
    TYPEORM_HOST: ${self:custom.AURORA.HOST}
    TYPEORM_PORT: ${self:custom.AURORA.PORT}
    TYPEORM_USER: ${self:custom.USERNAME}
    TYPEORM_PASSWORD: ${self:custom.PASSWORD}
    TYPEORM_DB: ${self:custom.DB_NAME}
    JWT_SECRET: secret

plugins:
  - serverless-plugin-typescript
  - serverless-plugin-optimize
  - serverless-offline

package:
  individually: true

custom:
  DB_NAME: db_name
  USERNAME: user
  PASSWORD: pwd
  AURORA:
    HOST:
      Fn::GetAtt: [AuroraRDSCluster, Endpoint.Address]
    PORT:
      Fn::GetAtt: [AuroraRDSCluster, Endpoint.Port]
  optimize:
    external: ['swagger-ui-dist']

resources:
  Resources:
    LambdaRole: ${file(./infra-serverless/LambdaRole.yml)}
    AuroraRDSCluster: ${file(./infra-serverless/AuroraRDSCluster.yml)}

functions:
  index:
    handler: src/lambda.handler
    events:
      - http:
          cors: true
          path: '/{proxy+}'
          method: any

All my other routes work, I have authentication flow with jwt, I have no problem with them

Try with:

functions:
  main:
    handler: src/lambda.handler
    events:
      - http:
          method: any
          path: /{any+}

It finally work !! 馃槃
The problem was here:
lambda.ts

await nestApp.init();
setupSwagger(nestApp);

I copied https://gist.github.com/csakbalint/7fe406bd1b15124180a988c87d57cf9b from the original author to make my test but nestApp init has to be call before the setupSwagger function..

setupSwagger(nestApp);
await nestApp.init();

Thank you very much for your time @plorencrstit ! I Appreciate it!

@csakbalint there is an error in your gist, look upper you switched your setupSwagger function with await nestApp.init(); one.

@plorencrstit Thank you very much, you saved my day!!

Hello guys!
I have the same problem, but in serveless offline, the swagger works. When I access the aws endpoint, he didn't work. My lambda is similar of @nathanagez. Anyone can help me?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yuval-hazaz picture yuval-hazaz  路  3Comments

cdiaz picture cdiaz  路  4Comments

ericzon picture ericzon  路  4Comments

djedlajn picture djedlajn  路  4Comments

ivashog picture ivashog  路  3Comments