Skip to content
Branch: master
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
..
Failed to load latest commit information.
README.md
api.ts
apikey.ts
cognitoAuthorizer.ts
index.ts
lambdaAuthorizer.ts
metrics.ts
requestValidator.ts
swagger_json.ts

README.md

Pulumi API Gateway Components

Pulumi's API for simplifying working with API Gateway. The API currently provides ways to define routes that accepts and forwards traffic to a specified destination. A route is a publicly accessible URI that supports the defined HTTP methods and responds according to the route definition.

Defining an Endpoint

To define an endpoint you will need to specify a route. You can also define the stage name (else it will default to "stage"). A stage is an addressable instance of the Rest API.

Routes

The destination is determined by the route, which can be an Event Handler Route, a Static Route, an Integration Route or a Raw Data Route.

Event Handler Route

An Event Handler Route is a route that will map to a Lambda. You will need to specify the path, method and the Lambda. Pulumi allows you to define the Lambda inline with your application code and provisions the appropriate permissions on your behalf so that API Gateway can communicate with your Lambda.

import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/",
        method: "GET",
        eventHandler: async (event) => {
            // This code runs in an AWS Lambda and will be invoked any time `/` is hit.
            return {
                statusCode: 200,
                body: "hello",
            };
        },
    }],
})

A complete example can be found here.

You can also link a route to an existing Lambda using aws.lambda.Function.get.

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/",
        method: "GET",
        eventHandler: aws.lambda.Function.get("example", "your_lambda_id"),
    }],
})

Additionally, you can control the Lambda that is created by calling new aws.lambda.CallbackFunction.

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/",
        method: "GET",
        eventHandler: new aws.lambda.CallbackFunction("test", {
            memorySize: 256,
            callback: async (event) => {
                return {
                    statusCode: 200,
                    body: "<h1>Hello world!</h1>",
                };
            },
        }),
    }],
})

Static Route

A Static Route is a route that will map to static content in files/directories. You will need to define the local path and then the files (and subdirectories) will be uploaded into S3 objects. If the local path points to a file, you can specify the content-type. Else, the content types for all files in a directory are inferred.

By default, any request on directory will serve index.html. This behavior can be disabled by setting the index field to false.

import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/www",
        localPath: "www",
        index: false,
    }],
})

A complete example can be found here.

Integration Route

An Integration Route is a route that will map an endpoint to a specified backend. The supported types are:

* `http` or `http_proxy`: integration with an HTTP backend
* `aws_proxy`: integration with AWS Lambda functions
* `aws`: integration with AWS Lambda functions or other AWS services, such as Amazon DynamoDB, Amazon Simple Notification Service or Amazon Simple Queue Service
* `mock`: integration with API Gateway without invoking any backend
import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/integration",
        target: {
            uri: "https://www.google.com",
            type: "http_proxy",
        },
    }],
})

For more information API Integrations, visit the AWS documentation.

Raw Data Route

A Raw Data Route is a fallback route for when raw swagger control is desired. The data field should be an object that will be then included in the final swagger specification. For more information on the x-amazon-apigateway-integration swagger object, visit the AWS documentation.

import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/rawdata",
        method: "GET",
        data: {
            "x-amazon-apigateway-integration": {
                "uri": "https://www.google.com/",
                "responses": {
                    "default": {
                        "statusCode": "200",
                    },
                },
                "passthroughBehavior": "when_no_match",
                "httpMethod": "GET",
                "type": "http_proxy",
            },
        },
    }],
})

Request Validation

API Gateway can perform basic validations against request parameters, a request payload or both. When a validation fails, a 400 error is returned immediately.

Validators

Validators can be assigned at the API level or at the method level. The validators defined at a method level override any validator set at the API level.

You must specify one of the following validators:

  • "ALL" - validate both the request body and request parameters
  • "BODY_ONLY" - validate only the request body
  • "PARAMS_ONLY" - validate only the request parameters
import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/www",
        localPath: "www",
        index: false,
        requestValidator: "PARAMS_ONLY",
    }],
    requestValidator: "ALL",
})

Request Parameters

For each required request parameter, you must define the name and where the parameter is expected (i.e. "path", "query", or "header").

import * as awsx from "@pulumi/awsx";

let endpoint = new awsx.apigateway.API("example", {
    routes: [{
        path: "/www",
        localPath: "www",
        index: false,
        requestValidator: "PARAMS_ONLY",
        requiredParams: [{
            name: "key",
            in: "query",
        }]
    }],
})

Request Body

Request body validation is currently not supported. If you have a strong use case, please comment on this open issue.

API Keys

To require an API Key for an API Gateway route you set the apiKeyRequired property equal to true. At the API level, you can choose if you want the API Key source to be HEADER (i.e. client includes a x-api-key header with the API Key) or AUTHORIZER (i.e. a Lambda authorizer sends the API Key as part of the authorization response). If the API Key source is not set, then the source will default to HEADER.

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        path: "/a",
        method: "GET",
        eventHandler: async () => {
            return {
                statusCode: 200,
                body: "<h1>Hello world!</h1>",
            };
        },
        apiKeyRequired: true,
    }],
    apikeySource: "AUTHORIZER",
});

You will also need to create a usage plan (new aws.apigateway.UsagePlan) and an API key (new aws.apigateway.ApiKey) and then associate the key with the usage plan (new aws.apigateway.UsagePlanKey). To simplify the creation of API Keys associated with your API you can use awsx.apigateway.createAssociatedAPIKeys, which create a Usage Plan, API Keys and associates the API Keys by creating a UsagePlanKey. Below is an example of using this helper function:

import * as awsx from "@pulumi/awsx";

const apikeys = awsx.apigateway.createAssociatedAPIKeys("my-api-keys", {
    apis: [api],
    apiKeys: [{
        name: "test-key",
    }],
});

 // Export the API Key if desired
export const apiKeyValue = apikeys.keys[0].apikey.value;

awsx.apigateway.createAssociatedAPIKeys will return an object that contains the Usage Plan, API Keys and Usage Plan Keys. Instead of providing the APIs, you can also specify the api stages for the Usage Plan as follows:

import * as awsx from "@pulumi/awsx";

const apikeys = awsx.apigateway.createAssociatedAPIKeys("my-api-keys", {
    usagePlan: {
        apiStages: [{
            apiId: api.restAPI.id,
            stage: api.stage.stageName,
        }],
    },
    apiKeys: [{
        name: "test-key",
    }],
});

Lambda Authorizers

Lambda Authorizers are AWS Lambda functions that provide control access to an API. You can define a Lambda Authorizer for an Event Handler Route or a Static Route. API Gateway supports request or token type Lambda authorizers. A token Lambda Authorizer uses an authorization token (i.e. a header in the form Authorization: Token <token>) to authorize the user, whereas a request Lambda Authorizer uses the request parameters (i.e. headers, path parameter or query parameters).

To define an Authorizer, you provide a Lambda that fulfills aws.lambda.EventHandler<AuthorizerEvent, AuthorizerResponse> or you provide information on a pre-existing Lambda authorizer. The example below shows defining the Authorizer Lambda directly inline. See the Event Handler Route section for other ways you can define a Lambda for the Authorizer.

Request Authorizer

Below is an example of a custom request Lambda Authorizer that uses awsx.apigateway.getRequestLambdaAuthorizer to simplify defining the authorizer.

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        path: "/b",
        method: "GET",
        eventHandler: async () => {
            return {
                statusCode: 200,
                body: "<h1>Hello world!</h1>",
            };
        },
        authorizers: [awsx.apigateway.getRequestLambdaAuthorizer({
            queryParameters: ["auth"],
            handler: async (event: awsx.apigateway.AuthorizerEvent) => {
                // Add your own custom authorization logic here.
                // Access the headers using event.headers, the query parameters using
                // event.queryStringParameters or path parameters using event.pathParameters
                return awsx.apigateway.authorizerResponse("user", "Allow", event.methodArn);
            },
        })],
    }],
});

You may also define the authorizer by specifying all the values. As seen below:

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        ...
        authorizers: [{
            authorizerName: "prettyAuthorizer",
            parameterName: "auth",
            parameterLocation: "query",
            authType: "custom",
            type: "request",
            handler: async (event: awsx.apigateway.AuthorizerEvent) => {
                // Add your own custom authorization logic here.
                return awsx.apigateway.authorizerResponse(
                    "user",
                    "Allow",
                    event.methodArn);
            },
            identitySource: ["method.request.querystring.auth"],
        }],
    }],
});

Token Authorizer

Below is an example of a custom token Lambda Authorizer that uses awsx.apigateway. to simplify the creation of the authorizer.

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        path: "/b",
        method: "GET",
        eventHandler: async () => {
            return {
                statusCode: 200,
                body: "<h1>Hello world!</h1>",
            };
        },
        authorizers: [awsx.apigateway.getTokenLambdaAuthorizer({
            handler: async (event: awsx.apigateway.AuthorizerEvent) => {
                // Add your own custom authorization logic here.
                const token = event.authorizationToken;
                if (token === "Allow") {
                    return awsx.apigateway.authorizerResponse("user","Allow", event.methodArn);
                }
                return awsx.apigateway.authorizerResponse("user", "Deny", event.methodArn);
            },
        })],
    }],
});

You may also define the authorizer by specifying all the values. As seen below:

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        path: "/b",
        method: "GET",
        eventHandler: async () => {
            return {
                statusCode: 200,
                body: "<h1>Hello world!</h1>",
            };
        },
        authorizers: [{
            parameterName: "Authorization",
            parameterLocation: "header",
            authType: "oauth2",
            type: "request",
            handler: async (event: awsx.apigateway.AuthorizerEvent) => {
                // Add your own custom authorization logic here.
                 return awsx.apigateway.authorizerResponse("user", "Allow", event.methodArn);
            },
        }],
    }],
});

Specifying the Role

If your Authorizer requires access to other AWS resources, you will need to provision the appropriate role. You can do so by using new aws.lambda.CallbackFunction.

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const callbackFxn = new aws.lambda.CallbackFunction("callbackFxn", {
    callback: async (event: awsx.apigateway.AuthorizerEvent) => {
        // Add custom authorization logic here
        return awsx.apigateway.authorizerResponse("user", "Allow", event.methodArn);
    },
    role: role, // Specify role with appropriate AWS permissions.
});

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        path: "/b",
        method: "GET",
        eventHandler: async () => {
            return {
                statusCode: 200,
                body: "<h1>Hello world!</h1>",
            };
        },
        authorizers: [{
            parameterName: "Authorization",
            parameterLocation: "header",
            authType: "oauth2",
            type: "request",
            handler: callbackFxn,
        }],
    }],
});

Using a Pre-existing AWS Lambda

You can also define the Lambda Authorizer elsewhere and then reference the required values.

import * as awsx from "@pulumi/awsx";

const apiWithAuthorizer = new awsx.apigateway.API("authorizer-api", {
    routes: [{
        ...
        authorizers: [{
            authorizerName: "testing",
            parameterName: "auth",
            parameterLocation: "query",
            authType: "custom",
            type: "request",
            handler: {
                // Either specify the aws.lambda.Function or provide the invoke URI
                uri: authorizerLambda,
                credentials: gatewayRole.arn,
            },
            identitySource: ["method.request.querystring.auth"],
        }],
    }],
});

A complete example of defining the Lambda Authorizer elsewhere can be found here.

Authorizer Response

A helper function awsx.apigateway.authorizerResponse has been created to simplify generating the authorizer response. This can be used when defining the authorizer handler as follows:

import * as awsx from "@pulumi/awsx";

const api = new awsx.apigateway.API("myapi", {
    routes: [{
        ...
        authorizers: [{
            header: "Authorization",
            handler: async (event: awsx.apigateway.AuthorizerEvent) => {
                // Add your own custom authorization logic here.
                const token = event.authorizationToken;
                if (token === "Allow") {
                    return awsx.apigateway.authorizerResponse("user", "Allow", event.methodArn);
                }
                return awsx.apigateway.authorizerResponse("user", "Deny", event.methodArn);
            },
        }],
    }],
});

Cognito Authorizers

Cognito Authorizers allow you to use Amazon Cognito User Pools as an Authorizer for API Gateway. This will require users to sign in to the user pool, obtain an identity/access token and then call your API with said token.

import * as awsx from "@pulumi/awsx";

// Create an AWS Cognito User Pool
const cognitoUserPool = new aws.cognito.UserPool("pool", {});

// Create an API that requires authorizes against the User Pool
const apiWithCognitoAuthorizer = new awsx.apigateway.API("cognito-protected-api", {
    routes: [{
        path: "/www_old",
        localPath: "www",
        authorizers: [awsx.apigateway.getCognitoAuthorizer({
            providerARNs: [cognitoUserPool],
        })],
    }],
});

Swagger String

You can use a OpenAPI specification that is in string form to initialize the API Gateway. This in a way is an escape hatch for implementing featured not yet supported by Pulumi. You must manually provide permission for any route targets to be invoked by API Gateway when using this option.

import * as awsx from "@pulumi/awsx";

const swaggerSpec = {
    swagger: "2.0",
    info: { title: "api", version: "1.0" },
    ...
};

let endpoint = new awsx.apigateway.API("example", {
    swaggerString: JSON.stringify(swaggerSpec),
    stageName: "dev",
})
You can’t perform that action at this time.