2
votes

I'm not entirely sure what is wrong with my aws api-gateway setup. I have two regions I use, one for my staging (eu-west-1) environment and another for my live (us-east-1) environment.

When I build and run my api in staging, all works fine. However when I try to run my api on live, I get the following error:

{"message": "Internal server error"}

To try and debug this I ran the API using the 'test' functionality in the aws console and performed a GET request. To my surprise I noticed that the region in the request header was wrong (eu-west-1 instead of us-east-1). Also the test returned the following message with a 502 response:

{"Message":"Functions from 'us-east-1' are not reachable in this region ('eu-west-1')","Type":"User"}

Does this mean that my api is being run in the eu-west-1 region?

If I check my region in the console I am clearly in us-east-1 when running the test. Also the region in my api-gateway uri is us-east-1.

https://.execute-api.us-east-1.amazonaws.com/prod

I can see that my request header has: Host=lambda.eu-west-1.amazonaws.com and in the output I have the following property:

Endpoint request URI: https://lambda.eu-west-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1::function:/invocations

I have no idea why my regions are mixed up! I thought it might have something to do with my build process, but after double checking everything I am not able to see what could be causing it. I am hoping a fresh set of eyes could pick something up!

To build my api I use a combination of a swagger.yaml file and a cloudformation.json file.

SWAGGER: I have placeholders in this file which I replace running a node script before sending the file to aws.

---
swagger: 2.0
info:
  title: ServerlessExpress
basePath: /YOUR_API_GATEWAY_STAGE
schemes:
- https
paths:
  /:
    x-amazon-apigateway-any-method:
      produces:
      - application/json
      responses:
        200:
          description: 200 response
          schema:
            $ref: "#/definitions/Empty"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: 200
        uri: arn:aws:apigateway:YOUR_AWS_REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:YOUR_AWS_REGION:YOUR_ACCOUNT_ID:function:api-gateway-service/invocations
        passthroughBehavior: when_no_match
        httpMethod: POST
        type: aws_proxy
    options:
      consumes:
      - application/json
      produces:
      - application/json
      responses:
        200:
          description: 200 response
          schema:
            $ref: "#/definitions/Empty"
          headers:
            Access-Control-Allow-Origin:
              type: string
            Access-Control-Allow-Methods:
              type: string
            Access-Control-Allow-Headers:
              type: string
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: 200
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS,POST'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        passthroughBehavior: when_no_match
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        type: mock
  /{proxy+}:
    x-amazon-apigateway-any-method:
      produces:
      - application/json
      parameters:
      - name: proxy
        in: path
        required: true
        type: string
      responses: {}
      x-amazon-apigateway-integration:
        uri: arn:aws:apigateway:YOUR_AWS_REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:YOUR_AWS_REGION:YOUR_ACCOUNT_ID:function:api-gateway-service/invocations
        httpMethod: POST
        type: aws_proxy
    options:
      consumes:
      - application/json
      produces:
      - application/json
      responses:
        200:
          description: 200 response
          schema:
            $ref: "#/definitions/Empty"
          headers:
            Access-Control-Allow-Origin:
              type: string
            Access-Control-Allow-Methods:
              type: string
            Access-Control-Allow-Headers:
              type: string
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: 200
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS,POST'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        passthroughBehavior: when_no_match
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        type: mock
definitions:
  Empty:
    type: object
    title: Empty Schema

CLOUDFORMATION:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "AWS Serverless Express.",
    "Parameters": {
        "AwsServerlessExpressS3Bucket": {
            "Type": "String",
            "Description": "The S3 bucket in which the lambda function code is stored. Bucket names are region-unique, so you must change this."
        },
        "LambdaFunctionS3Key": {
            "Type": "String",
            "AllowedPattern": ".*\\.zip",
            "Description": "The S3 object for the lambda function code package.",
            "Default": "lambda-function.zip"
        },
        "ApiGatewaySwaggerS3Key": {
            "Type": "String",
            "AllowedPattern": ".*\\.yaml",
            "Description": "The S3 object for the swagger definition of the API Gateway API.",
            "Default": "simple-proxy-api.yaml"
        }
    },

    "Resources": {
        "ApiGatewayApi": {
            "Type": "AWS::ApiGateway::RestApi",
            "Properties": {
                "Description": "AWS Serverless Express API",
                "BodyS3Location": {
                    "Bucket": {
                        "Ref": "ServerlessExpressBucket"
                    },
                    "Key": {
                        "Ref": "ApiGatewaySwaggerS3Key"
                    }
                }
            }
        },

        "ApiGatewayApiDeployment": {
            "Type": "AWS::ApiGateway::Deployment",
            "Properties": {
                "RestApiId": {
                    "Ref": "ApiGatewayApi"
                },
                "StageName": "YOUR_API_GATEWAY_STAGE"
            }
        },

        "LambdaApiGatewayExecutionPermission": {
            "Type": "AWS::Lambda::Permission",
            "Properties": {
                "Action": "lambda:InvokeFunction",
                "FunctionName": {
                    "Fn::GetAtt": ["LambdaFunction", "Arn"]
                },
                "Principal": "apigateway.amazonaws.com",
                "SourceArn": {
                    "Fn::Join": ["", ["arn:aws:execute-api:", {
                        "Ref": "AWS::Region"
                    }, ":", {
                        "Ref": "AWS::AccountId"
                    }, ":", {
                        "Ref": "ApiGatewayApi"
                    }, "/*/*"]]
                }
            }
        },

        "LambdaFunction": {
            "Type": "AWS::Lambda::Function",
            "Properties": {
                "Code": {
                    "S3Bucket": {
                        "Ref": "ServerlessExpressBucket"
                    },
                    "S3Key": {
                        "Ref": "LambdaFunctionS3Key"
                    }
                },
                "FunctionName": "api-gateway-service",
                "Handler": "lambda.serverlessExpress",
                "Description": "Service running on api-gateway",
                "MemorySize": 128,
                "Role": {
                    "Fn::Join": ["", ["arn:aws:iam::", {
                        "Ref": "AWS::AccountId"
                    }, ":role/service-lambda"]]
                },
                "Runtime": "nodejs4.3",
                "Timeout": 30
            }
        }
    },

    "Outputs": {
        "LambdaFunctionConsoleUrl": {
            "Description": "Console URL for the Lambda Function.",
            "Value": {
                "Fn::Join": ["", ["https://", {
                    "Ref": "AWS::Region"
                }, ".console.aws.amazon.com/lambda/home?region=", {
                    "Ref": "AWS::Region"
                }, "#/functions/", {
                    "Ref": "LambdaFunction"
                }]]
            }
        },
        "ApiGatewayApiConsoleUrl": {
            "Description": "Console URL for the API Gateway API's Stage.",
            "Value": {
                "Fn::Join": ["", ["https://", {
                    "Ref": "AWS::Region"
                }, ".console.aws.amazon.com/apigateway/home?region=", {
                    "Ref": "AWS::Region"
                }, "#/apis/", {
                    "Ref": "ApiGatewayApi"
                }, "/stages/YOUR_API_GATEWAY_STAGE"]]
            }
        },
        "ApiUrl": {
            "Description": "Invoke URL for your API. Clicking this link will perform a GET request on the root resource of your API.",
            "Value": {
                "Fn::Join": ["", ["https://", {
                    "Ref": "ApiGatewayApi"
                }, ".execute-api.", {
                    "Ref": "AWS::Region"
                }, ".amazonaws.com/YOUR_API_GATEWAY_STAGE/"]]
            }
        }
    }
}
1

1 Answers

1
votes

Turns out I had manually created the lambda function that api-gateway calls. Although cloudformation updated this code, there seemed to be a region mix-up going on behind the scenes.

So in short, simply deleting the stack in cloudformation and the lambda function I had manually created, re-running the build and letting cloudformation to build the lambda function solves the problem!