Skip to content

spreaker/grunt-aws-apigateway

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

grunt-aws-apigateway

A grunt plugin to easily configure and deploy AWS API Gateway.

Scope

AWS API Gateway configuration through the web console takes lot of mouse clicks and is error prone. This grunt plugin allows you to script and automatically deploy your API Gateway configuration.

Install

npm install grunt-aws-apigateway --save-dev

Usage

The following usage example could look a bit verbose at a first glance. However, AWS API Gateway setup is pretty complex and the following resources structure tries to map as much close as possible the AWS API, in order to provide the same degree of flexibility.

grunt.initConfig({
    apigateway_deploy: {
        options: {
            accessKeyId: "key",
            secretAccessKey: "secret",
            region: "us-east-1"
        },
        default: {
            restApiId: "xxx",
            deployment: {
                stageName: "prod"
            },
            resources: {
                "/users": {
                    methods: {
                        GET: {
                            integration: {
                                type: "AWS",
                                uri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:xxx:function:getUsers/invocations",
                                integrationHttpMethod: "POST",
                                requestTemplates: {
                                    "application/json": JSON.stringify({
                                        "filter": "$input.params('filter')"
                                    })
                                }
                            },
                            responses: {
                                200: {
                                    // Pass-through
                                    responseModels: {
                                        "application/json": "Empty"
                                    }
                                },
                                400: {
                                    selectionPattern: "error code: 400",
                                    responseTemplates: {
                                        "application/json": JSON.stringify({"error": "$input.path('$.errorMessage')"})
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
});

grunt.loadNpmTasks('grunt-aws-apigateway');

grunt.registerTask(
    "deploy-api",
    "Deploy the API Gateway config",
    ["apigateway_deploy"]
);

Features

What you can do:

  • Create API resources
  • Configure resource's Method Request, Integration Request, Method Response, Integration Response
  • Deploy API changes to a stage

What you can't do:

  • Create models

One time configuration you should do by hand:

  • Create a new API
  • Create stages (once created, the plugin will deploy the API to the configured stage)
  • Create an IAM user with the policy required to deploy your API
  • Add permission to each Lambda function will get invoked by API Gateway (in case you're integration API Gateway with AWS Lambda functions). Troubleshooting section explains how to do it.

NOTE: to ease the development of this plugin, each run deletes all resources and re-creates them. This means that it doesn't apply differential changes and if you've already created some resources that are not part of plugin configuration, you will loose it at the first run. In other words, make sure the plugin configuration contains all resources of your API.

Configuration

The plugin config is made of 3 required properties:

  • restApiId (your API Gateway id)
  • resources
  • deployment

resources

The resources property contains the configuration of all your API Resources. Resources are organized in a tree, the path must start with a / and each resource's full path is built concatenating together all parent resources paths.

Example - create /tweets/trends resource:

{
    resources: {
        "/tweets": {
            "/trends": {}
        }
    }
}

Each resource can have zero or more methods. For each method you must define a request and response integration (ie. a AWS Lambda function).

Example - add GET method to /tweets/trends resource:

{
    resources: {
        "/tweets": {
            "/trends": {
                methods: {
                    GET: {
                        authorizationType: "NONE",
                        apiKeyRequired: false,
                        integration: { /* Integration Request config */ },
                        responses: { /* Integration Response config */ }
                    }
                }
            }
        }
    }
}

The resource's Integration Request config must contain the integration type and uri, along with other optional settings (ie. requestTemplates).

Example - integrate a lambda function to GET /tweets/trends:

integration: {
    type: "AWS",
    uri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:xxx:function:getUsers/invocations",
    integrationHttpMethod: "POST", // Lambda functions must be called with a POST
    credentials: undefined,
    requestParameters: {},
    cacheNamespace: undefined,
    cacheKeyParameters: [],
    requestTemplates: {
        "application/json": JSON.stringify({
            "filter": "$input.params('filter')"
        })
    }
}

The resource's Integration Response config is a map whose keys are the status codes, and the value is the configuration for each status code.

Example - integrate 200 and 400 response codes:

responses: {
    200: {
        responseModels: {
            "application/json": "Empty"
        },
        responseParameters: {},
        responseTemplates: {}
    },
    400: {
        selectionPattern: "error code: 400",
        responseParameters: {},
        responseTemplates: {
            "application/json": JSON.stringify({"error": "$input.path('$.errorMessage')"})
        }
    }
}

deployment

The last step of apigateway_deploy is to deploy all the changes to a stage. The configuration of this phase is made through the deployment property. stageName is the only required property.

{
    deployment: {
        stageName: "prod",
        cacheClusterEnabled: false,
        cacheClusterSize: "1G"
        description: "",
        stageDescription: "",
        variables: []
    }
}

Options

options.region

AWS region where you would like to deploy your API.

options.accessKeyId and options.secretAccessKey

If you prefer to use hardcoded AWS credentials, you should both set accessKeyId and secretAccessKey.

options.credentialsJSON

If you prefer to use AWS credentials stored in a JSON file, you should set the JSON file path here.

options.profile

If you prefer to use a specific AWS credentials profile you can set it here.

Troubleshooting

"Internal server error" due to "Invalid permissions on Lambda function"

This error occurs when you didn't add permission to run the Lambda function from the API Gateway service. To fix it, run the following command:

$ aws lambda add-permission --function-name "<your function name>" --action "lambda:InvokeFunction" --principal "apigateway.amazonaws.com" --source-arn "<your api gateway endpoint arn>" --statement-id "522028352"

Example:

aws lambda add-permission --function-name "getUsers" --action "lambda:InvokeFunction" --principal "apigateway.amazonaws.com" --source-arn "arn:aws:execute-api:us-east-1:123456789:abcdefg/*/GET/users" --statement-id "522028352"

Contributing

You're very welcome to contribute to this pluging, in case you spot any bug, or to add some missing features (ie. create models). Please do your best to:

  • Keep the coding style
  • Keep your code as much clean (and readable) as possible

License

MIT