tbd_
tbd_

Reputation: 1248

502 "Internal Server Error" with API Gateway + Lambda when deploying

I'm using an API-Gateway + Lambda combo to process a POST request. I'm using Node + Serverless Framework.

When I run serverless offline, I am able to send a POST request and have my data stored on an S3. But when I deploy it and run the same POST request, I get a "502 Internal Server Error" message. Because it works locally but not in production, I'm pretty sure I have some permission/config problems.

    saveToS3(newData)
      .then(result => {
        callback(null, {
          statusCode: 200,
          headers: { 'Content-Type': 'application/json' },
          body: "Successfully added data!"
        });
      })
      .catch(e => callback(null, { statusCode: 500, body: JSON.stringify(e) }));

What I've checked:

What I haven't checked:

My yml:

service: myService

provider:
  name: aws
  runtime: nodejs12.x

  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "s3:GetObject"
        - "s3:PutObject"
      Resource: "arn:aws:s3:::myS3Bucket/*"

functions:
  saveToS3:
    handler: handler.saveToS3
    events:
      - http:
          path: users
          method: post
          cors: true
plugins:
  - serverless-offline

resources:
 Resources:
   NewResource:
     Type: AWS::S3::Bucket
     Properties:
       BucketName: myS3Bucket

Upvotes: 2

Views: 9778

Answers (4)

Rax
Rax

Reputation: 81

I'm using CDK. In my case I added the parameter binaryMediaTypes: ["application/json"], which is used incorrectly:

    const myApi = new ApiGw.RestApi(this, "my-api", {
        restApiName: `my-awesome-api`,
        defaultCorsPreflightOptions: {
            allowOrigins: ApiGw.Cors.ALL_ORIGINS,
            allowMethods: ApiGw.Cors.ALL_METHODS,
            allowHeaders: ["Content-Type", "Accept", ...],
        },
        ...
        binaryMediaTypes: ["application/json"], // <-- Problematic property
});

binaryMediaTypes is useful when you create an API that will serve as a proxy of a specific AWS service (e.g. S3), and you will send binary data, like images, documents, etc.

Removing binaryMediaTypes from the API definition, it worked like a charm

Upvotes: 0

user1653042
user1653042

Reputation: 403

In our case, we are using serverless + API Gateway + Lambda. Our main app.ts exports an async handler wrapped by serverless. Ex (EnvironmentService is just a service layer for the environment config):

const allowedBinaryMimeTypes = EnvironmentService.getFileMimeTypesAllowed();
...
const handler = serverless(app, { binary: allowedBinaryMimeTypes });

Before modifying any code, the 502 Bad Gateway Error log was showing this (AWS CloudWatch):

enter image description here

enter image description here

Our solution was to override the default aws provider timeout in serverless.yml:

where to add override variable

S3Service file (call to getObject):

    static async getObject(type: string, pathParams: APIGatewayProxyEventPathParameters): Promise<any> {
        const params = await this.setRequestParams(type, pathParams.id, pathParams.fileName);

        try {
            // get S3 object/file
            const data = await S3.getObject(params).promise();

            // some bug with AWS converting JPG objects to JPEGg
            const contentType = data.ContentType === 'image/jpeg' ? 'image/jpg' : data.ContentType;

            return {
                statusCode: 200,
                headers: {
                    'Access-Control-Allow-Headers': 'Content-Type',
                    'Access-Control-Allow-Origin': '*', // Required for CORS support to work
                    'Access-Control-Allow-Methods': 'OPTIONS,GET',
                    'Content-Type': contentType
                },
                body: data.Body.toString('base64'),
                isBase64Encoded: true
            };
        } catch (err) {
            console.error(err);
            throw err;
        }
    }

Upvotes: 0

tbd_
tbd_

Reputation: 1248

Found the issue, facepalming because it took me hours to find it.

I had two problems:

  • My main lambda function had an "async" in front of it, but I was implementing it with callbacks. Removing the "async" fixed it.

  • My response format was missing the "headers" and "isBase64Encoded" fields. Including that removed the 502 error (see below).

Helpful links: - https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format - (if you're using serverless framework) https://github.com/dherault/serverless-offline/issues/405

If using API Gateway, make sure your lambda function's response looks like the code snippet below. Otherwise it will throw a "502 - Malformed Lambda Function" error.

{
    "isBase64Encoded": true|false,
    "statusCode": httpStatusCode,
    "headers": { "headerName": "headerValue", ... },
    "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
    "body": "..."
}

Upvotes: 4

user8936011
user8936011

Reputation:

If you are using proxy integration you need to be careful because for every possible syntax error it will throw an internal server error.

catch(e => callback(null, { statusCode: 500, body: JSON.stringify(e) }));

Can the error be not setting the headers here? If not it might probably be a syntax error.

Upvotes: 1

Related Questions