Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serverless issue #199

Closed
csakbalint opened this issue Mar 5, 2019 · 13 comments
Closed

Serverless issue #199

csakbalint opened this issue Mar 5, 2019 · 13 comments

Comments

@csakbalint
Copy link

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

@jtmthf
Copy link

jtmthf commented Mar 26, 2019

@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.

@plorencrstit
Copy link

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?

@nathanagez
Copy link

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

@plorencrstit
Copy link

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;
};

@nathanagez
Copy link

@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 à 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;
};

@plorencrstit
Copy link

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.

  entities: [`${__dirname}/../**/*.entity{.ts,.js}`],
  ...typeOrmConfigGeneral,
};

export const typeOrmConfigServerless: TypeOrmModuleOptions = {
  entities: [
    Category,
    Comment,
    Discussion,
  ],
  ...typeOrmConfigGeneral,
};

I choose the configuration based on some env.

Do you use typeorm?

@nathanagez
Copy link

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 à 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 ?

@plorencrstit
Copy link

Show the entire serverless.yml, please.

@nathanagez
Copy link

nathanagez commented Apr 22, 2020

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

@plorencrstit
Copy link

Try with:

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

@nathanagez
Copy link

nathanagez commented Apr 22, 2020

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.

@tuna-date
Copy link

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

@wagnerlinharesm
Copy link

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?

@nestjs nestjs locked and limited conversation to collaborators Mar 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants