# Amazon API Gateway Construct Library
<!--BEGIN STABILITY BANNER-->---
![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)
![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)
---
<!--END STABILITY BANNER-->
Amazon API Gateway is a fully managed service that makes it easy for developers
to publish, maintain, monitor, and secure APIs at any scale. Create an API to
access data, business logic, or functionality from your back-end services, such
as applications running on Amazon Elastic Compute Cloud (Amazon EC2), code
running on AWS Lambda, or any web application.
## Table of Contents
* [Defining APIs](#defining-apis)
* [Breaking up Methods and Resources across Stacks](#breaking-up-methods-and-resources-across-stacks)
* [AWS Lambda-backed APIs](#aws-lambda-backed-apis)
* [AWS StepFunctions backed APIs](#aws-stepfunctions-backed-APIs)
* [Integration Targets](#integration-targets)
* [Usage Plan & API Keys](#usage-plan--api-keys)
* [Working with models](#working-with-models)
* [Default Integration and Method Options](#default-integration-and-method-options)
* [Proxy Routes](#proxy-routes)
* [Authorizers](#authorizers)
* [IAM-based authorizer](#iam-based-authorizer)
* [Lambda-based token authorizer](#lambda-based-token-authorizer)
* [Lambda-based request authorizer](#lambda-based-request-authorizer)
* [Cognito User Pools authorizer](#cognito-user-pools-authorizer)
* [Mutual TLS](#mutal-tls-mtls)
* [Deployments](#deployments)
* [Deep dive: Invalidation of deployments](#deep-dive-invalidation-of-deployments)
* [Custom Domains](#custom-domains)
* [Access Logging](#access-logging)
* [Cross Origin Resource Sharing (CORS)](#cross-origin-resource-sharing-cors)
* [Endpoint Configuration](#endpoint-configuration)
* [Private Integrations](#private-integrations)
* [Gateway Response](#gateway-response)
* [OpenAPI Definition](#openapi-definition)
* [Endpoint configuration](#endpoint-configuration)
* [Metrics](#metrics)
* [APIGateway v2](#apigateway-v2)
## Defining APIs
APIs are defined as a hierarchy of resources and methods. `addResource` and
`addMethod` can be used to build this hierarchy. The root resource is
`api.root`.
For example, the following code defines an API that includes the following HTTP
endpoints: `ANY /`, `GET /books`, `POST /books`, `GET /books/{book_id}`, `DELETE /books/{book_id}`.
```python
api = apigateway.RestApi(self, "books-api")
api.root.add_method("ANY")
books = api.root.add_resource("books")
books.add_method("GET")
books.add_method("POST")
book = books.add_resource("{book_id}")
book.add_method("GET")
book.add_method("DELETE")
```
## AWS Lambda-backed APIs
A very common practice is to use Amazon API Gateway with AWS Lambda as the
backend integration. The `LambdaRestApi` construct makes it easy:
The following code defines a REST API that routes all requests to the
specified AWS Lambda function:
```python
# backend: lambda.Function
apigateway.LambdaRestApi(self, "myapi",
handler=backend
)
```
You can also supply `proxy: false`, in which case you will have to explicitly
define the API model:
```python
# backend: lambda.Function
api = apigateway.LambdaRestApi(self, "myapi",
handler=backend,
proxy=False
)
items = api.root.add_resource("items")
items.add_method("GET") # GET /items
items.add_method("POST") # POST /items
item = items.add_resource("{item}")
item.add_method("GET") # GET /items/{item}
# the default integration for methods is "handler", but one can
# customize this behavior per method or even a sub path.
item.add_method("DELETE", apigateway.HttpIntegration("http://amazon.com"))
```
## AWS StepFunctions backed APIs
You can use Amazon API Gateway with AWS Step Functions as the backend integration, specifically Synchronous Express Workflows.
The `StepFunctionsRestApi` only supports integration with Synchronous Express state machine. The `StepFunctionsRestApi` construct makes this easy by setting up input, output and error mapping.
The construct sets up an API endpoint and maps the `ANY` HTTP method and any calls to the API endpoint starts an express workflow execution for the underlying state machine.
Invoking the endpoint with any HTTP method (`GET`, `POST`, `PUT`, `DELETE`, ...) in the example below will send the request to the state machine as a new execution. On success, an HTTP code `200` is returned with the execution output as the Response Body.
If the execution fails, an HTTP `500` response is returned with the `error` and `cause` from the execution output as the Response Body. If the request is invalid (ex. bad execution input) HTTP code `400` is returned.
The response from the invocation contains only the `output` field from the
[StartSyncExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html#API_StartSyncExecution_ResponseSyntax) API.
In case of failures, the fields `error` and `cause` are returned as part of the response.
Other metadata such as billing details, AWS account ID and resource ARNs are not returned in the API response.
By default, a `prod` stage is provisioned.
In order to reduce the payload size sent to AWS Step Functions, `headers` are not forwarded to the Step Functions execution input. It is possible to choose whether `headers`, `requestContext`, `path`, `querystring`, and `authorizer` are included or not. By default, `headers` are excluded in all requests.
More details about AWS Step Functions payload limit can be found at https://docs.aws.amazon.com/step-functions/latest/dg/limits-overview.html#service-limits-task-executions.
The following code defines a REST API that routes all requests to the specified AWS StepFunctions state machine:
```python
state_machine_definition = stepfunctions.Pass(self, "PassState")
state_machine = stepfunctions.StateMachine(self, "StateMachine",
definition=state_machine_definition,
state_machine_type=stepfunctions.StateMachineType.EXPRESS
)
apigateway.StepFunctionsRestApi(self, "StepFunctionsRestApi",
deploy=True,
state_machine=state_machine
)
```
When the REST API endpoint configuration above is invoked using POST, as follows -
```bash
curl -X POST -d '{ "customerId": 1 }' https://example.com/
```
AWS Step Functions will receive the request body in its input as follows:
```json
{
"body": {
"customerId": 1
},
"path": "/",
"querystring": {}
}
```
When the endpoint is invoked at path '/users/5' using the HTTP GET method as below:
```bash
curl -X GET https://example.com/users/5?foo=bar
```
AWS Step Functions will receive the following execution input:
```json
{
"body": {},
"path": {
"users": "5"
},
"querystring": {
"foo": "bar"
}
}
```
Additional information around the request such as the request context, authorizer context, and headers can be included as part of the input
forwarded to the state machine. The following example enables headers to be included in the input but not query string.
```python
apigateway.StepFunctionsRestApi(self, "StepFunctionsRestApi",
state_machine=machine,
headers=True,
path=False,
querystring=False,
authorizer=False,
request_context=apigateway.RequestContext(
caller=True,
user=True
)
)
```
In such a case, when the endpoint is invoked as below:
```bash
curl -X GET https://example.com/
```
AWS Step Functions will receive the following execution input:
```json
{
"headers": {
"Accept": "...",
"CloudFront-Forwarded-Proto": "...",
},
"requestContext": {
"accountId": "...",
"apiKey": "...",
},
"body": {}
}
```
### Breaking up Methods and Resources across Stacks
It is fairly common for REST APIs with a large number of Resources and Methods to hit the [CloudFormation
limit](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) of 500 resources per
stack.
To help with this, Resources and Methods for the same REST API can be re-organized across multiple stacks. A common
way to do this is to have a stack per Resource or groups of Resources, but this is not the only possible way.
The following example uses sets up two Resources '/pets' and '/books' in separate stacks using nested stacks:
```python
from aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse, IntegrationResponse, MethodResponse
from aws_cdk.core import App, CfnOutput, NestedStack, NestedStackProps, Stack
from constructs import Construct
from aws_cdk.aws_apigateway import Deployment, Method, MockIntegration, PassthroughBehavior, RestApi, Stage
#
# This file showcases how to split up a RestApi's Resources and Methods across nested stacks.
#
# The root stack 'RootStack' first defines a RestApi.
# Two nested stacks BooksStack and PetsStack, create corresponding Resources '/books' and '/pets'.
# They are then deployed to a 'prod' Stage via a third nested stack - DeployStack.
#
# To verify this worked, go to the APIGateway
#
class RootStack(Stack):
def __init__(self, scope):
super().__init__(scope, "integ-restapi-import-RootStack")
rest_api = RestApi(self, "RestApi",
deploy=False
)
rest_api.root.add_method("ANY")
pets_stack = PetsStack(self,
rest_api_id=rest_api.rest_api_id,
root_resource_id=rest_api.rest_api_root_resource_id
)
books_stack = BooksStack(self,
rest_api_id=rest_api.rest_api_id,
root_resource_id=rest_api.rest_api_root_resource_id
)
DeployStack(self,
rest_api_id=rest_api.rest_api_id,
methods=pets_stack.methods.concat(books_stack.methods)
)
CfnOutput(self, "PetsURL",
value=f"https://{restApi.restApiId}.execute-api.{this.region}.amazonaws.com/prod/pets"
)
CfnOutput(self, "BooksURL",
value=f"https://{restApi.restApiId}.execute-api.{this.region}.amazonaws.com/prod/books"
)
class PetsStack(NestedStack):
def __init__(self, scope, *, restApiId, rootResourceId, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):
super().__init__(scope, "integ-restapi-import-PetsStack", restApiId=restApiId, rootResourceId=rootResourceId, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)
api = RestApi.from_rest_api_attributes(self, "RestApi",
rest_api_id=rest_api_id,
root_resource_id=root_resource_id
)
method = api.root.add_resource("pets").add_method("GET", MockIntegration(
integration_responses=[IntegrationResponse(
status_code="200"
)],
passthrough_behavior=PassthroughBehavior.NEVER,
request_templates={
"application/json": "{ \"statusCode\": 200 }"
}
),
method_responses=[MethodResponse(status_code="200")]
)
self.methods.push(method)
class BooksStack(NestedStack):
def __init__(self, scope, *, restApiId, rootResourceId, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):
super().__init__(scope, "integ-restapi-import-BooksStack", restApiId=restApiId, rootResourceId=rootResourceId, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)
api = RestApi.from_rest_api_attributes(self, "RestApi",
rest_api_id=rest_api_id,
root_resource_id=root_resource_id
)
method = api.root.add_resource("books").add_method("GET", MockIntegration(
integration_responses=[IntegrationResponse(
status_code="200"
)],
passthrough_behavior=PassthroughBehavior.NEVER,
request_templates={
"application/json": "{ \"statusCode\": 200 }"
}
),
method_responses=[MethodResponse(status_code="200")]
)
self.methods.push(method)
class DeployStack(NestedStack):
def __init__(self, scope, *, restApiId, methods=None, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):
super().__init__(scope, "integ-restapi-import-DeployStack", restApiId=restApiId, methods=methods, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)
deployment = Deployment(self, "Deployment",
api=RestApi.from_rest_api_id(self, "RestApi", rest_api_id)
)
if methods:
for method in methods:
deployment.node.add_dependency(method)
Stage(self, "Stage", deployment=deployment)
RootStack(App())
```
## Integration Targets
Methods are associated with backend integrations, which are invoked when this
method is called. API Gateway supports the following integrations:
* `MockIntegration` - can be used to test APIs. This is the default
integration if one is not specified.
* `LambdaIntegration` - can be used to invoke an AWS Lambda function.
* `AwsIntegration` - can be used to invoke arbitrary AWS service APIs.
* `HttpIntegration` - can be used to invoke HTTP endpoints.
The following example shows how to integrate the `GET /book/{book_id}` method to
an AWS Lambda function:
```python
# get_book_handler: lambda.Function
# book: apigateway.Resource
get_book_integration = apigateway.LambdaIntegration(get_book_handler)
book.add_method("GET", get_book_integration)
```
Integration options can be optionally be specified:
```python
# get_book_handler: lambda.Function
# get_book_integration: apigateway.LambdaIntegration
get_book_integration = apigateway.LambdaIntegration(get_book_handler,
content_handling=apigateway.ContentHandling.CONVERT_TO_TEXT, # convert to base64
credentials_passthrough=True
)
```
Method options can optionally be specified when adding methods:
```python
# book: apigateway.Resource
# get_book_integration: apigateway.LambdaIntegration
book.add_method("GET", get_book_integration,
authorization_type=apigateway.AuthorizationType.IAM,
api_key_required=True
)
```
It is possible to also integrate with AWS services in a different region. The following code integrates with Amazon SQS in the
`eu-west-1` region.
```python
get_message_integration = apigateway.AwsIntegration(
service="sqs",
path="queueName",
region="eu-west-1"
)
```
## Usage Plan & API Keys
A usage plan specifies who can access one or more deployed API stages and methods, and the rate at which they can be
accessed. The plan uses API keys to identify API clients and meters access to the associated API stages for each key.
Usage plans also allow configuring throttling limits and quota limits that are enforced on individual client API keys.
The following example shows how to create and asscociate a usage plan and an API key:
```python
# integration: apigateway.LambdaIntegration
api = apigateway.RestApi(self, "hello-api")
v1 = api.root.add_resource("v1")
echo = v1.add_resource("echo")
echo_method = echo.add_method("GET", integration, api_key_required=True)
plan = api.add_usage_plan("UsagePlan",
name="Easy",
throttle=apigateway.ThrottleSettings(
rate_limit=10,
burst_limit=2
)
)
key = api.add_api_key("ApiKey")
plan.add_api_key(key)
```
To associate a plan to a given RestAPI stage:
```python
# plan: apigateway.UsagePlan
# api: apigateway.RestApi
# echo_method: apigateway.Method
plan.add_api_stage(
stage=api.deployment_stage,
throttle=[apigateway.ThrottlingPerMethod(
method=echo_method,
throttle=apigateway.ThrottleSettings(
rate_limit=10,
burst_limit=2
)
)
]
)
```
Existing usage plans can be imported into a CDK app using its id.
```python
imported_usage_plan = apigateway.UsagePlan.from_usage_plan_id(self, "imported-usage-plan", "<usage-plan-key-id>")
```
The name and value of the API Key can be specified at creation; if not
provided, a name and value will be automatically generated by API Gateway.
```python
# api: apigateway.RestApi
key = api.add_api_key("ApiKey",
api_key_name="myApiKey1",
value="MyApiKeyThatIsAtLeast20Characters"
)
```
Existing API keys can also be imported into a CDK app using its id.
```python
imported_key = apigateway.ApiKey.from_api_key_id(self, "imported-key", "<api-key-id>")
```
The "grant" methods can be used to give prepackaged sets of permissions to other resources. The
following code provides read permission to an API key.
```python
# imported_key: apigateway.ApiKey
# lambda_fn: lambda.Function
imported_key.grant_read(lambda_fn)
```
### ⚠️ Multiple API Keys
It is possible to specify multiple API keys for a given Usage Plan, by calling `usagePlan.addApiKey()`.
When using multiple API keys, a past bug of the CDK prevents API key associations to a Usage Plan to be deleted.
If the CDK app had the [feature flag](https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html) - `@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId` - enabled when the API
keys were created, then the app will not be affected by this bug.
If this is not the case, you will need to ensure that the CloudFormation [logical ids](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html) of the API keys that are not
being deleted remain unchanged.
Make note of the logical ids of these API keys before removing any, and set it as part of the `addApiKey()` method:
```python
# usageplan: apigateway.UsagePlan
# api_key: apigateway.ApiKey
usageplan.add_api_key(api_key,
override_logical_id="..."
)
```
### Rate Limited API Key
In scenarios where you need to create a single api key and configure rate limiting for it, you can use `RateLimitedApiKey`.
This construct lets you specify rate limiting properties which should be applied only to the api key being created.
The API key created has the specified rate limits, such as quota and throttles, applied.
The following example shows how to use a rate limited api key :
```python
# api: apigateway.RestApi
key = apigateway.RateLimitedApiKey(self, "rate-limited-api-key",
customer_id="hello-customer",
resources=[api],
quota=apigateway.QuotaSettings(
limit=10000,
period=apigateway.Period.MONTH
)
)
```
## Working with models
When you work with Lambda integrations that are not Proxy integrations, you
have to define your models and mappings for the request, response, and integration.
```python
hello = lambda_.Function(self, "hello",
runtime=lambda_.Runtime.NODEJS_14_X,
handler="hello.handler",
code=lambda_.Code.from_asset("lambda")
)
api = apigateway.RestApi(self, "hello-api")
resource = api.root.add_resource("v1")
```
You can define more parameters on the integration to tune the behavior of API Gateway
```python
# hello: lambda.Function
integration = apigateway.LambdaIntegration(hello,
proxy=False,
request_parameters={
# You can define mapping parameters from your method to your integration
# - Destination parameters (the key) are the integration parameters (used in mappings)
# - Source parameters (the value) are the source request parameters or expressions
# @see: https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html
"integration.request.querystring.who": "method.request.querystring.who"
},
allow_test_invoke=True,
request_templates={
# You can define a mapping that will build a payload for your integration, based
# on the integration parameters that you have specified
# Check: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
"application/json": JSON.stringify({"action": "sayHello", "poll_id": "$util.escapeJavaScript($input.params('who'))"})
},
# This parameter defines the behavior of the engine is no suitable response template is found
passthrough_behavior=apigateway.PassthroughBehavior.NEVER,
integration_responses=[apigateway.IntegrationResponse(
# Successful response from the Lambda function, no filter defined
# - the selectionPattern filter only tests the error message
# We will set the response status code to 200
status_code="200",
response_templates={
# This template takes the "message" result from the Lambda function, and embeds it in a JSON response
# Check https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
"application/json": JSON.stringify({"state": "ok", "greeting": "$util.escapeJavaScript($input.body)"})
},
response_parameters={
# We can map response parameters
# - Destination parameters (the key) are the response parameters (used in mappings)
# - Source parameters (the value) are the integration response parameters or expressions
"method.response.header.Content-Type": "'application/json'",
"method.response.header.Access-Control-Allow-Origin": "'*'",
"method.response.header.Access-Control-Allow-Credentials": "'true'"
}
), apigateway.IntegrationResponse(
# For errors, we check if the error message is not empty, get the error data
selection_pattern="(\n|.)+",
# We will set the response status code to 200
status_code="400",
response_templates={
"application/json": JSON.stringify({"state": "error", "message": "$util.escapeJavaScript($input.path('$.errorMessage'))"})
},
response_parameters={
"method.response.header.Content-Type": "'application/json'",
"method.response.header.Access-Control-Allow-Origin": "'*'",
"method.response.header.Access-Control-Allow-Credentials": "'true'"
}
)
]
)
```
You can define models for your responses (and requests)
```python
# api: apigateway.RestApi
# We define the JSON Schema for the transformed valid response
response_model = api.add_model("ResponseModel",
content_type="application/json",
model_name="ResponseModel",
schema=apigateway.JsonSchema(
schema=apigateway.JsonSchemaVersion.DRAFT4,
title="pollResponse",
type=apigateway.JsonSchemaType.OBJECT,
properties={
"state": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING),
"greeting": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING)
}
)
)
# We define the JSON Schema for the transformed error response
error_response_model = api.add_model("ErrorResponseModel",
content_type="application/json",
model_name="ErrorResponseModel",
schema=apigateway.JsonSchema(
schema=apigateway.JsonSchemaVersion.DRAFT4,
title="errorResponse",
type=apigateway.JsonSchemaType.OBJECT,
properties={
"state": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING),
"message": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING)
}
)
)
```
And reference all on your method definition.
```python
# integration: apigateway.LambdaIntegration
# resource: apigateway.Resource
# response_model: apigateway.Model
# error_response_model: apigateway.Model
resource.add_method("GET", integration,
# We can mark the parameters as required
request_parameters={
"method.request.querystring.who": True
},
# we can set request validator options like below
request_validator_options=apigateway.RequestValidatorOptions(
request_validator_name="test-validator",
validate_request_body=True,
validate_request_parameters=False
),
method_responses=[apigateway.MethodResponse(
# Successful response from the integration
status_code="200",
# Define what parameters are allowed or not
response_parameters={
"method.response.header.Content-Type": True,
"method.response.header.Access-Control-Allow-Origin": True,
"method.response.header.Access-Control-Allow-Credentials": True
},
# Validate the schema on the response
response_models={
"application/json": response_model
}
), apigateway.MethodResponse(
# Same thing for the error responses
status_code="400",
response_parameters={
"method.response.header.Content-Type": True,
"method.response.header.Access-Control-Allow-Origin": True,
"method.response.header.Access-Control-Allow-Credentials": True
},
response_models={
"application/json": error_response_model
}
)
]
)
```
Specifying `requestValidatorOptions` automatically creates the RequestValidator construct with the given options.
However, if you have your RequestValidator already initialized or imported, use the `requestValidator` option instead.
## Default Integration and Method Options
The `defaultIntegration` and `defaultMethodOptions` properties can be used to
configure a default integration at any resource level. These options will be
used when defining method under this resource (recursively) with undefined
integration or options.
> If not defined, the default integration is `MockIntegration`. See reference
> documentation for default method options.
The following example defines the `booksBackend` integration as a default
integration. This means that all API methods that do not explicitly define an
integration will be routed to this AWS Lambda function.
```python
# books_backend: apigateway.LambdaIntegration
api = apigateway.RestApi(self, "books",
default_integration=books_backend
)
books = api.root.add_resource("books")
books.add_method("GET") # integrated with `booksBackend`
books.add_method("POST") # integrated with `booksBackend`
book = books.add_resource("{book_id}")
book.add_method("GET")
```
A Method can be configured with authorization scopes. Authorization scopes are
used in conjunction with an [authorizer that uses Amazon Cognito user
pools](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html#apigateway-enable-cognito-user-pool).
Read more about authorization scopes
[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html#cfn-apigateway-method-authorizationscopes).
Authorization scopes for a Method can be configured using the `authorizationScopes` property as shown below -
```python
# books: apigateway.Resource
books.add_method("GET", apigateway.HttpIntegration("http://amazon.com"),
authorization_type=apigateway.AuthorizationType.COGNITO,
authorization_scopes=["Scope1", "Scope2"]
)
```
## Proxy Routes
The `addProxy` method can be used to install a greedy `{proxy+}` resource
on a path. By default, this also installs an `"ANY"` method:
```python
# resource: apigateway.Resource
# handler: lambda.Function
proxy = resource.add_proxy(
default_integration=apigateway.LambdaIntegration(handler),
# "false" will require explicitly adding methods on the `proxy` resource
any_method=True
)
```
## Authorizers
API Gateway [supports several different authorization types](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html)
that can be used for controlling access to your REST APIs.
### IAM-based authorizer
The following CDK code provides 'execute-api' permission to an IAM user, via IAM policies, for the 'GET' method on the `books` resource:
```python
# books: apigateway.Resource
# iam_user: iam.User
get_books = books.add_method("GET", apigateway.HttpIntegration("http://amazon.com"),
authorization_type=apigateway.AuthorizationType.IAM
)
iam_user.attach_inline_policy(iam.Policy(self, "AllowBooks",
statements=[
iam.PolicyStatement(
actions=["execute-api:Invoke"],
effect=iam.Effect.ALLOW,
resources=[get_books.method_arn]
)
]
))
```
### Lambda-based token authorizer
API Gateway also allows [lambda functions to be used as authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).
This module provides support for token-based Lambda authorizers. When a client makes a request to an API's methods configured with such
an authorizer, API Gateway calls the Lambda authorizer, which takes the caller's identity as input and returns an IAM policy as output.
A token-based Lambda authorizer (also called a token authorizer) receives the caller's identity in a bearer token, such as
a JSON Web Token (JWT) or an OAuth token.
API Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format.
The event object that the handler is called with contains the `authorizationToken` and the `methodArn` from the request to the
API Gateway endpoint. The handler is expected to return the `principalId` (i.e. the client identifier) and a `policyDocument` stating
what the client is authorizer to perform.
See [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) for a detailed specification on
inputs and outputs of the Lambda handler.
The following code attaches a token-based Lambda authorizer to the 'GET' Method of the Book resource:
```python
# auth_fn: lambda.Function
# books: apigateway.Resource
auth = apigateway.TokenAuthorizer(self, "booksAuthorizer",
handler=auth_fn
)
books.add_method("GET", apigateway.HttpIntegration("http://amazon.com"),
authorizer=auth
)
```
A full working example is shown below.
!cdk-integ pragma:ignore-assets
```python
from aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse
import path as path
import aws_cdk.aws_lambda as lambda_
from aws_cdk.core import App, Stack
from aws_cdk.aws_apigateway import MockIntegration, PassthroughBehavior, RestApi, TokenAuthorizer
#
# Stack verification steps:
# * `curl -s -o /dev/null -w "%{http_code}" <url>` should return 401
# * `curl -s -o /dev/null -w "%{http_code}" -H 'Authorization: deny' <url>` should return 403
# * `curl -s -o /dev/null -w "%{http_code}" -H 'Authorization: allow' <url>` should return 200
#
app = App()
stack = Stack(app, "TokenAuthorizerInteg")
authorizer_fn = lambda_.Function(stack, "MyAuthorizerFunction",
runtime=lambda_.Runtime.NODEJS_14_X,
handler="index.handler",
code=lambda_.AssetCode.from_asset(path.join(__dirname, "integ.token-authorizer.handler"))
)
restapi = RestApi(stack, "MyRestApi")
authorizer = TokenAuthorizer(stack, "MyAuthorizer",
handler=authorizer_fn
)
restapi.root.add_method("ANY", MockIntegration(
integration_responses=[IntegrationResponse(status_code="200")
],
passthrough_behavior=PassthroughBehavior.NEVER,
request_templates={
"application/json": "{ \"statusCode\": 200 }"
}
),
method_responses=[MethodResponse(status_code="200")
],
authorizer=authorizer
)
```
By default, the `TokenAuthorizer` looks for the authorization token in the request header with the key 'Authorization'. This can,
however, be modified by changing the `identitySource` property.
Authorizers can also be passed via the `defaultMethodOptions` property within the `RestApi` construct or the `Method` construct. Unless
explicitly overridden, the specified defaults will be applied across all `Method`s across the `RestApi` or across all `Resource`s,
depending on where the defaults were specified.
### Lambda-based request authorizer
This module provides support for request-based Lambda authorizers. When a client makes a request to an API's methods configured with such
an authorizer, API Gateway calls the Lambda authorizer, which takes specified parts of the request, known as identity sources,
as input and returns an IAM policy as output. A request-based Lambda authorizer (also called a request authorizer) receives
the identity sources in a series of values pulled from the request, from the headers, stage variables, query strings, and the context.
API Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format.
The event object that the handler is called with contains the body of the request and the `methodArn` from the request to the
API Gateway endpoint. The handler is expected to return the `principalId` (i.e. the client identifier) and a `policyDocument` stating
what the client is authorizer to perform.
See [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) for a detailed specification on
inputs and outputs of the Lambda handler.
The following code attaches a request-based Lambda authorizer to the 'GET' Method of the Book resource:
```python
# auth_fn: lambda.Function
# books: apigateway.Resource
auth = apigateway.RequestAuthorizer(self, "booksAuthorizer",
handler=auth_fn,
identity_sources=[apigateway.IdentitySource.header("Authorization")]
)
books.add_method("GET", apigateway.HttpIntegration("http://amazon.com"),
authorizer=auth
)
```
A full working example is shown below.
!cdk-integ pragma:ignore-assets
```python
from aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse
import path as path
import aws_cdk.aws_lambda as lambda_
from aws_cdk.core import App, Stack
from aws_cdk.aws_apigateway import MockIntegration, PassthroughBehavior, RestApi
from aws_cdk.aws_apigateway import RequestAuthorizer
from aws_cdk.aws_apigateway import IdentitySource
# Against the RestApi endpoint from the stack output, run
# `curl -s -o /dev/null -w "%{http_code}" <url>` should return 401
# `curl -s -o /dev/null -w "%{http_code}" -H 'Authorization: deny' <url>?allow=yes` should return 403
# `curl -s -o /dev/null -w "%{http_code}" -H 'Authorization: allow' <url>?allow=yes` should return 200
app = App()
stack = Stack(app, "RequestAuthorizerInteg")
authorizer_fn = lambda_.Function(stack, "MyAuthorizerFunction",
runtime=lambda_.Runtime.NODEJS_14_X,
handler="index.handler",
code=lambda_.AssetCode.from_asset(path.join(__dirname, "integ.request-authorizer.handler"))
)
restapi = RestApi(stack, "MyRestApi")
authorizer = RequestAuthorizer(stack, "MyAuthorizer",
handler=authorizer_fn,
identity_sources=[IdentitySource.header("Authorization"), IdentitySource.query_string("allow")]
)
restapi.root.add_method("ANY", MockIntegration(
integration_responses=[IntegrationResponse(status_code="200")
],
passthrough_behavior=PassthroughBehavior.NEVER,
request_templates={
"application/json": "{ \"statusCode\": 200 }"
}
),
method_responses=[MethodResponse(status_code="200")
],
authorizer=authorizer
)
```
By default, the `RequestAuthorizer` does not pass any kind of information from the request. This can,
however, be modified by changing the `identitySource` property, and is required when specifying a value for caching.
Authorizers can also be passed via the `defaultMethodOptions` property within the `RestApi` construct or the `Method` construct. Unless
explicitly overridden, the specified defaults will be applied across all `Method`s across the `RestApi` or across all `Resource`s,
depending on where the defaults were specified.
### Cognito User Pools authorizer
API Gateway also allows [Amazon Cognito user pools as authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html)
The following snippet configures a Cognito user pool as an authorizer:
```python
# books: apigateway.Resource
user_pool = cognito.UserPool(self, "UserPool")
auth = apigateway.CognitoUserPoolsAuthorizer(self, "booksAuthorizer",
cognito_user_pools=[user_pool]
)
books.add_method("GET", apigateway.HttpIntegration("http://amazon.com"),
authorizer=auth,
authorization_type=apigateway.AuthorizationType.COGNITO
)
```
## Mutual TLS (mTLS)
Mutual TLS can be configured to limit access to your API based by using client certificates instead of (or as an extension of) using authorization headers.
```python
# acm: Any
apigateway.DomainName(self, "domain-name",
domain_name="example.com",
certificate=acm.Certificate.from_certificate_arn(self, "cert", "arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d"),
mtls=apigateway.MTLSConfig(
bucket=s3.Bucket(self, "bucket"),
key="truststore.pem",
version="version"
)
)
```
Instructions for configuring your trust store can be found [here](https://aws.amazon.com/blogs/compute/introducing-mutual-tls-authentication-for-amazon-api-gateway/).
## Deployments
By default, the `RestApi` construct will automatically create an API Gateway
[Deployment](https://docs.aws.amazon.com/apigateway/api-reference/resource/deployment/) and a "prod" [Stage](https://docs.aws.amazon.com/apigateway/api-reference/resource/stage/) which represent the API configuration you
defined in your CDK app. This means that when you deploy your app, your API will
be have open access from the internet via the stage URL.
The URL of your API can be obtained from the attribute `restApi.url`, and is
also exported as an `Output` from your stack, so it's printed when you `cdk deploy` your app:
```console
$ cdk deploy
...
books.booksapiEndpointE230E8D5 = https://6lyktd4lpk.execute-api.us-east-1.amazonaws.com/prod/
```
To disable this behavior, you can set `{ deploy: false }` when creating your
API. This means that the API will not be deployed and a stage will not be
created for it. You will need to manually define a `apigateway.Deployment` and
`apigateway.Stage` resources.
Use the `deployOptions` property to customize the deployment options of your
API.
The following example will configure API Gateway to emit logs and data traces to
AWS CloudWatch for all API calls:
> By default, an IAM role will be created and associated with API Gateway to
> allow it to write logs and metrics to AWS CloudWatch unless `cloudWatchRole` is
> set to `false`.
```python
api = apigateway.RestApi(self, "books",
deploy_options=apigateway.StageOptions(
logging_level=apigateway.MethodLoggingLevel.INFO,
data_trace_enabled=True
)
)
```
### Deep dive: Invalidation of deployments
API Gateway deployments are an immutable snapshot of the API. This means that we
want to automatically create a new deployment resource every time the API model
defined in our CDK app changes.
In order to achieve that, the AWS CloudFormation logical ID of the
`AWS::ApiGateway::Deployment` resource is dynamically calculated by hashing the
API configuration (resources, methods). This means that when the configuration
changes (i.e. a resource or method are added, configuration is changed), a new
logical ID will be assigned to the deployment resource. This will cause
CloudFormation to create a new deployment resource.
By default, old deployments are *deleted*. You can set `retainDeployments: true`
to allow users revert the stage to an old deployment manually.
## Custom Domains
To associate an API with a custom domain, use the `domainName` configuration when
you define your API:
```python
# acm_certificate_for_example_com: Any
api = apigateway.RestApi(self, "MyDomain",
domain_name=apigateway.DomainNameOptions(
domain_name="example.com",
certificate=acm_certificate_for_example_com
)
)
```
This will define a `DomainName` resource for you, along with a `BasePathMapping`
from the root of the domain to the deployment stage of the API. This is a common
set up.
To route domain traffic to an API Gateway API, use Amazon Route 53 to create an
alias record. An alias record is a Route 53 extension to DNS. It's similar to a
CNAME record, but you can create an alias record both for the root domain, such
as `example.com`, and for subdomains, such as `www.example.com`. (You can create
CNAME records only for subdomains.)
```python
import aws_cdk.aws_route53 as route53
import aws_cdk.aws_route53_targets as targets
# api: apigateway.RestApi
# hosted_zone_for_example_com: Any
route53.ARecord(self, "CustomDomainAliasRecord",
zone=hosted_zone_for_example_com,
target=route53.RecordTarget.from_alias(targets.ApiGateway(api))
)
```
You can also define a `DomainName` resource directly in order to customize the default behavior:
```python
# acm_certificate_for_example_com: Any
apigateway.DomainName(self, "custom-domain",
domain_name="example.com",
certificate=acm_certificate_for_example_com,
endpoint_type=apigateway.EndpointType.EDGE, # default is REGIONAL
security_policy=apigateway.SecurityPolicy.TLS_1_2
)
```
Once you have a domain, you can map base paths of the domain to APIs.
The following example will map the URL [https://example.com/go-to-api1](https://example.com/go-to-api1)
to the `api1` API and [https://example.com/boom](https://example.com/boom) to the `api2` API.
```python
# domain: apigateway.DomainName
# api1: apigateway.RestApi
# api2: apigateway.RestApi
domain.add_base_path_mapping(api1, base_path="go-to-api1")
domain.add_base_path_mapping(api2, base_path="boom")
```
You can specify the API `Stage` to which this base path URL will map to. By default, this will be the
`deploymentStage` of the `RestApi`.
```python
# domain: apigateway.DomainName
# restapi: apigateway.RestApi
beta_deploy = apigateway.Deployment(self, "beta-deployment",
api=restapi
)
beta_stage = apigateway.Stage(self, "beta-stage",
deployment=beta_deploy
)
domain.add_base_path_mapping(restapi, base_path="api/beta", stage=beta_stage)
```
If you don't specify `basePath`, all URLs under this domain will be mapped
to the API, and you won't be able to map another API to the same domain:
```python
# domain: apigateway.DomainName
# api: apigateway.RestApi
domain.add_base_path_mapping(api)
```
This can also be achieved through the `mapping` configuration when defining the
domain as demonstrated above.
If you wish to setup this domain with an Amazon Route53 alias, use the `targets.ApiGatewayDomain`:
```python
# hosted_zone_for_example_com: Any
# domain_name: apigateway.DomainName
import aws_cdk.aws_route53 as route53
import aws_cdk.aws_route53_targets as targets
route53.ARecord(self, "CustomDomainAliasRecord",
zone=hosted_zone_for_example_com,
target=route53.RecordTarget.from_alias(targets.ApiGatewayDomain(domain_name))
)
```
## Access Logging
Access logging creates logs every time an API method is accessed. Access logs can have information on
who has accessed the API, how the caller accessed the API and what responses were generated.
Access logs are configured on a Stage of the RestApi.
Access logs can be expressed in a format of your choosing, and can contain any access details, with a
minimum that it must include the 'requestId'. The list of variables that can be expressed in the access
log can be found
[here](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference).
Read more at [Setting Up CloudWatch API Logging in API
Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html)
```python
# production stage
prd_log_group = logs.LogGroup(self, "PrdLogs")
api = apigateway.RestApi(self, "books",
deploy_options=apigateway.StageOptions(
access_log_destination=apigateway.LogGroupLogDestination(prd_log_group),
access_log_format=apigateway.AccessLogFormat.json_with_standard_fields()
)
)
deployment = apigateway.Deployment(self, "Deployment", api=api)
# development stage
dev_log_group = logs.LogGroup(self, "DevLogs")
apigateway.Stage(self, "dev",
deployment=deployment,
access_log_destination=apigateway.LogGroupLogDestination(dev_log_group),
access_log_format=apigateway.AccessLogFormat.json_with_standard_fields(
caller=False,
http_method=True,
ip=True,
protocol=True,
request_time=True,
resource_path=True,
response_length=True,
status=True,
user=True
)
)
```
The following code will generate the access log in the [CLF format](https://en.wikipedia.org/wiki/Common_Log_Format).
```python
log_group = logs.LogGroup(self, "ApiGatewayAccessLogs")
api = apigateway.RestApi(self, "books",
deploy_options=apigateway.StageOptions(
access_log_destination=apigateway.LogGroupLogDestination(log_group),
access_log_format=apigateway.AccessLogFormat.clf()
)
)
```
You can also configure your own access log format by using the `AccessLogFormat.custom()` API.
`AccessLogField` provides commonly used fields. The following code configures access log to contain.
```python
log_group = logs.LogGroup(self, "ApiGatewayAccessLogs")
apigateway.RestApi(self, "books",
deploy_options=apigateway.StageOptions(
access_log_destination=apigateway.LogGroupLogDestination(log_group),
access_log_format=apigateway.AccessLogFormat.custom(f"{apigateway.AccessLogField.contextRequestId()} {apigateway.AccessLogField.contextErrorMessage()} {apigateway.AccessLogField.contextErrorMessageString()}")
)
)
```
You can use the `methodOptions` property to configure
[default method throttling](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html#apigateway-api-level-throttling-in-usage-plan)
for a stage. The following snippet configures the a stage that accepts
100 requests per minute, allowing burst up to 200 requests per minute.
```python
api = apigateway.RestApi(self, "books")
deployment = apigateway.Deployment(self, "my-deployment", api=api)
stage = apigateway.Stage(self, "my-stage",
deployment=deployment,
method_options={
"/*/*": apigateway.MethodDeploymentOptions( # This special path applies to all resource paths and all HTTP methods
throttling_rate_limit=100,
throttling_burst_limit=200)
}
)
```
Configuring `methodOptions` on the `deployOptions` of `RestApi` will set the
throttling behaviors on the default stage that is automatically created.
```python
api = apigateway.RestApi(self, "books",
deploy_options=apigateway.StageOptions(
method_options={
"/*/*": apigateway.MethodDeploymentOptions( # This special path applies to all resource paths and all HTTP methods
throttling_rate_limit=100,
throttling_burst_limit=1000)
}
)
)
```
## Cross Origin Resource Sharing (CORS)
[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a mechanism
that uses additional HTTP headers to tell browsers to give a web application
running at one origin, access to selected resources from a different origin. A
web application executes a cross-origin HTTP request when it requests a resource
that has a different origin (domain, protocol, or port) from its own.
You can add the CORS [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests) OPTIONS
HTTP method to any API resource via the `defaultCorsPreflightOptions` option or by calling the `addCorsPreflight` on a specific resource.
The following example will enable CORS for all methods and all origins on all resources of the API:
```python
apigateway.RestApi(self, "api",
default_cors_preflight_options=apigateway.CorsOptions(
allow_origins=apigateway.Cors.ALL_ORIGINS,
allow_methods=apigateway.Cors.ALL_METHODS
)
)
```
The following example will add an OPTIONS method to the `myResource` API resource, which
only allows GET and PUT HTTP requests from the origin [https://amazon.com.](https://amazon.com.)
```python
# my_resource: apigateway.Resource
my_resource.add_cors_preflight(
allow_origins=["https://amazon.com"],
allow_methods=["GET", "PUT"]
)
```
See the
[`CorsOptions`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.CorsOptions.html)
API reference for a detailed list of supported configuration options.
You can specify defaults this at the resource level, in which case they will be applied to the entire resource sub-tree:
```python
# resource: apigateway.Resource
subtree = resource.add_resource("subtree",
default_cors_preflight_options=apigateway.CorsOptions(
allow_origins=["https://amazon.com"]
)
)
```
This means that all resources under `subtree` (inclusive) will have a preflight
OPTIONS added to them.
See [#906](https://github.com/aws/aws-cdk/issues/906) for a list of CORS
features which are not yet supported.
## Endpoint Configuration
API gateway allows you to specify an
[API Endpoint Type](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html).
To define an endpoint type for the API gateway, use `endpointConfiguration` property:
```python
api = apigateway.RestApi(self, "api",
endpoint_configuration=apigateway.EndpointConfiguration(
types=[apigateway.EndpointType.EDGE]
)
)
```
You can also create an association between your Rest API and a VPC endpoint. By doing so,
API Gateway will generate a new
Route53 Alias DNS record which you can use to invoke your private APIs. More info can be found
[here](https://docs.aws.amazon.com/apigateway/latest/developerguide/associate-private-api-with-vpc-endpoint.html).
Here is an example:
```python
# some_endpoint: ec2.IVpcEndpoint
api = apigateway.RestApi(self, "api",
endpoint_configuration=apigateway.EndpointConfiguration(
types=[apigateway.EndpointType.PRIVATE],
vpc_endpoints=[some_endpoint]
)
)
```
By performing this association, we can invoke the API gateway using the following format:
```plaintext
https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}
```
## Private Integrations
A private integration makes it simple to expose HTTP/HTTPS resources behind an
Amazon VPC for access by clients outside of the VPC. The private integration uses
an API Gateway resource of `VpcLink` to encapsulate connections between API
Gateway and targeted VPC resources.
The `VpcLink` is then attached to the `Integration` of a specific API Gateway
Method. The following code sets up a private integration with a network load
balancer -
```python
import aws_cdk.aws_elasticloadbalancingv2 as elbv2
vpc = ec2.Vpc(self, "VPC")
nlb = elbv2.NetworkLoadBalancer(self, "NLB",
vpc=vpc
)
link = apigateway.VpcLink(self, "link",
targets=[nlb]
)
integration = apigateway.Integration(
type=apigateway.IntegrationType.HTTP_PROXY,
options=apigateway.IntegrationOptions(
connection_type=apigateway.ConnectionType.VPC_LINK,
vpc_link=link
)
)
```
The uri for the private integration, in the case of a VpcLink, will be set to the DNS name of
the VPC Link's NLB. If the VPC Link has multiple NLBs or the VPC Link is imported or the DNS
name cannot be determined for any other reason, the user is expected to specify the `uri`
property.
Any existing `VpcLink` resource can be imported into the CDK app via the `VpcLink.fromVpcLinkId()`.
```python
awesome_link = apigateway.VpcLink.from_vpc_link_id(self, "awesome-vpc-link", "us-east-1_oiuR12Abd")
```
## Gateway response
If the Rest API fails to process an incoming request, it returns to the client an error response without forwarding the
request to the integration backend. API Gateway has a set of standard response messages that are sent to the client for
each type of error. These error responses can be configured on the Rest API. The list of Gateway responses that can be
configured can be found [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html).
Learn more about [Gateway
Responses](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html).
The following code configures a Gateway Response when the response is 'access denied':
```python
api = apigateway.RestApi(self, "books-api")
api.add_gateway_response("test-response",
type=apigateway.ResponseType.ACCESS_DENIED,
status_code="500",
response_headers={
"Access-Control-Allow-Origin": "test.com",
"test-key": "test-value"
},
templates={
"application/json": "{ \"message\": $context.error.messageString, \"statusCode\": \"488\", \"type\": \"$context.error.responseType\" }"
}
)
```
## OpenAPI Definition
CDK supports creating a REST API by importing an OpenAPI definition file. It currently supports OpenAPI v2.0 and OpenAPI
v3.0 definition files. Read more about [Configuring a REST API using
OpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html).
The following code creates a REST API using an external OpenAPI definition JSON file -
```python
# integration: apigateway.Integration
api = apigateway.SpecRestApi(self, "books-api",
api_definition=apigateway.ApiDefinition.from_asset("path-to-file.json")
)
books_resource = api.root.add_resource("books")
books_resource.add_method("GET", integration)
```
It is possible to use the `addResource()` API to define additional API Gateway Resources.
**Note:** Deployment will fail if a Resource of the same name is already defined in the Open API specification.
**Note:** Any default properties configured, such as `defaultIntegration`, `defaultMethodOptions`, etc. will only be
applied to Resources and Methods defined in the CDK, and not the ones defined in the spec. Use the [API Gateway
extensions to OpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html)
to configure these.
There are a number of limitations in using OpenAPI definitions in API Gateway. Read the [Amazon API Gateway important
notes for REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html#api-gateway-known-issues-rest-apis)
for more details.
**Note:** When starting off with an OpenAPI definition using `SpecRestApi`, it is not possible to configure some
properties that can be configured directly in the OpenAPI specification file. This is to prevent people duplication
of these properties and potential confusion.
### Endpoint configuration
By default, `SpecRestApi` will create an edge optimized endpoint.
This can be modified as shown below:
```python
# api_definition: apigateway.ApiDefinition
api = apigateway.SpecRestApi(self, "ExampleRestApi",
api_definition=api_definition,
endpoint_types=[apigateway.EndpointType.PRIVATE]
)
```
**Note:** For private endpoints you will still need to provide the
[`x-amazon-apigateway-policy`](https://docs.aws.amazon.com/apigateway/latest/developerguide/openapi-extensions-policy.html) and
[`x-amazon-apigateway-endpoint-configuration`](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)
in your openApi file.
## Metrics
The API Gateway service sends metrics around the performance of Rest APIs to Amazon CloudWatch.
These metrics can be referred to using the metric APIs available on the `RestApi` construct.
The APIs with the `metric` prefix can be used to get reference to specific metrics for this API. For example,
the method below refers to the client side errors metric for this API.
```python
api = apigateway.RestApi(self, "my-api")
client_error_metric = api.metric_client_error()
```
## APIGateway v2
APIGateway v2 APIs are now moved to its own package named `aws-apigatewayv2`. For backwards compatibility, existing
APIGateway v2 "CFN resources" (such as `CfnApi`) that were previously exported as part of this package, are still
exported from here and have been marked deprecated. However, updates to these CloudFormation resources, such as new
properties and new resource types will not be available.
Move to using `aws-apigatewayv2` to get the latest APIs and updates.
---
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.
Raw data
{
"_id": null,
"home_page": "https://github.com/aws/aws-cdk",
"name": "aws-cdk.aws-apigateway",
"maintainer": "",
"docs_url": null,
"requires_python": "~=3.7",
"maintainer_email": "",
"keywords": "",
"author": "Amazon Web Services",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/40/1c/91d12d887e8e46e2794d02c66b0c41cc577afabc2005d97d91b475c57b50/aws-cdk.aws-apigateway-1.203.0.tar.gz",
"platform": null,
"description": "# Amazon API Gateway Construct Library\n\n<!--BEGIN STABILITY BANNER-->---\n\n\n![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)\n\n![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)\n\n---\n<!--END STABILITY BANNER-->\n\nAmazon API Gateway is a fully managed service that makes it easy for developers\nto publish, maintain, monitor, and secure APIs at any scale. Create an API to\naccess data, business logic, or functionality from your back-end services, such\nas applications running on Amazon Elastic Compute Cloud (Amazon EC2), code\nrunning on AWS Lambda, or any web application.\n\n## Table of Contents\n\n* [Defining APIs](#defining-apis)\n\n * [Breaking up Methods and Resources across Stacks](#breaking-up-methods-and-resources-across-stacks)\n* [AWS Lambda-backed APIs](#aws-lambda-backed-apis)\n* [AWS StepFunctions backed APIs](#aws-stepfunctions-backed-APIs)\n* [Integration Targets](#integration-targets)\n* [Usage Plan & API Keys](#usage-plan--api-keys)\n* [Working with models](#working-with-models)\n* [Default Integration and Method Options](#default-integration-and-method-options)\n* [Proxy Routes](#proxy-routes)\n* [Authorizers](#authorizers)\n\n * [IAM-based authorizer](#iam-based-authorizer)\n * [Lambda-based token authorizer](#lambda-based-token-authorizer)\n * [Lambda-based request authorizer](#lambda-based-request-authorizer)\n * [Cognito User Pools authorizer](#cognito-user-pools-authorizer)\n* [Mutual TLS](#mutal-tls-mtls)\n* [Deployments](#deployments)\n\n * [Deep dive: Invalidation of deployments](#deep-dive-invalidation-of-deployments)\n* [Custom Domains](#custom-domains)\n* [Access Logging](#access-logging)\n* [Cross Origin Resource Sharing (CORS)](#cross-origin-resource-sharing-cors)\n* [Endpoint Configuration](#endpoint-configuration)\n* [Private Integrations](#private-integrations)\n* [Gateway Response](#gateway-response)\n* [OpenAPI Definition](#openapi-definition)\n\n * [Endpoint configuration](#endpoint-configuration)\n* [Metrics](#metrics)\n* [APIGateway v2](#apigateway-v2)\n\n## Defining APIs\n\nAPIs are defined as a hierarchy of resources and methods. `addResource` and\n`addMethod` can be used to build this hierarchy. The root resource is\n`api.root`.\n\nFor example, the following code defines an API that includes the following HTTP\nendpoints: `ANY /`, `GET /books`, `POST /books`, `GET /books/{book_id}`, `DELETE /books/{book_id}`.\n\n```python\napi = apigateway.RestApi(self, \"books-api\")\n\napi.root.add_method(\"ANY\")\n\nbooks = api.root.add_resource(\"books\")\nbooks.add_method(\"GET\")\nbooks.add_method(\"POST\")\n\nbook = books.add_resource(\"{book_id}\")\nbook.add_method(\"GET\")\nbook.add_method(\"DELETE\")\n```\n\n## AWS Lambda-backed APIs\n\nA very common practice is to use Amazon API Gateway with AWS Lambda as the\nbackend integration. The `LambdaRestApi` construct makes it easy:\n\nThe following code defines a REST API that routes all requests to the\nspecified AWS Lambda function:\n\n```python\n# backend: lambda.Function\n\napigateway.LambdaRestApi(self, \"myapi\",\n handler=backend\n)\n```\n\nYou can also supply `proxy: false`, in which case you will have to explicitly\ndefine the API model:\n\n```python\n# backend: lambda.Function\n\napi = apigateway.LambdaRestApi(self, \"myapi\",\n handler=backend,\n proxy=False\n)\n\nitems = api.root.add_resource(\"items\")\nitems.add_method(\"GET\") # GET /items\nitems.add_method(\"POST\") # POST /items\n\nitem = items.add_resource(\"{item}\")\nitem.add_method(\"GET\") # GET /items/{item}\n\n# the default integration for methods is \"handler\", but one can\n# customize this behavior per method or even a sub path.\nitem.add_method(\"DELETE\", apigateway.HttpIntegration(\"http://amazon.com\"))\n```\n\n## AWS StepFunctions backed APIs\n\nYou can use Amazon API Gateway with AWS Step Functions as the backend integration, specifically Synchronous Express Workflows.\n\nThe `StepFunctionsRestApi` only supports integration with Synchronous Express state machine. The `StepFunctionsRestApi` construct makes this easy by setting up input, output and error mapping.\n\nThe construct sets up an API endpoint and maps the `ANY` HTTP method and any calls to the API endpoint starts an express workflow execution for the underlying state machine.\n\nInvoking the endpoint with any HTTP method (`GET`, `POST`, `PUT`, `DELETE`, ...) in the example below will send the request to the state machine as a new execution. On success, an HTTP code `200` is returned with the execution output as the Response Body.\n\nIf the execution fails, an HTTP `500` response is returned with the `error` and `cause` from the execution output as the Response Body. If the request is invalid (ex. bad execution input) HTTP code `400` is returned.\n\nThe response from the invocation contains only the `output` field from the\n[StartSyncExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartSyncExecution.html#API_StartSyncExecution_ResponseSyntax) API.\nIn case of failures, the fields `error` and `cause` are returned as part of the response.\nOther metadata such as billing details, AWS account ID and resource ARNs are not returned in the API response.\n\nBy default, a `prod` stage is provisioned.\n\nIn order to reduce the payload size sent to AWS Step Functions, `headers` are not forwarded to the Step Functions execution input. It is possible to choose whether `headers`, `requestContext`, `path`, `querystring`, and `authorizer` are included or not. By default, `headers` are excluded in all requests.\n\nMore details about AWS Step Functions payload limit can be found at https://docs.aws.amazon.com/step-functions/latest/dg/limits-overview.html#service-limits-task-executions.\n\nThe following code defines a REST API that routes all requests to the specified AWS StepFunctions state machine:\n\n```python\nstate_machine_definition = stepfunctions.Pass(self, \"PassState\")\n\nstate_machine = stepfunctions.StateMachine(self, \"StateMachine\",\n definition=state_machine_definition,\n state_machine_type=stepfunctions.StateMachineType.EXPRESS\n)\n\napigateway.StepFunctionsRestApi(self, \"StepFunctionsRestApi\",\n deploy=True,\n state_machine=state_machine\n)\n```\n\nWhen the REST API endpoint configuration above is invoked using POST, as follows -\n\n```bash\ncurl -X POST -d '{ \"customerId\": 1 }' https://example.com/\n```\n\nAWS Step Functions will receive the request body in its input as follows:\n\n```json\n{\n \"body\": {\n \"customerId\": 1\n },\n \"path\": \"/\",\n \"querystring\": {}\n}\n```\n\nWhen the endpoint is invoked at path '/users/5' using the HTTP GET method as below:\n\n```bash\ncurl -X GET https://example.com/users/5?foo=bar\n```\n\nAWS Step Functions will receive the following execution input:\n\n```json\n{\n \"body\": {},\n \"path\": {\n \"users\": \"5\"\n },\n \"querystring\": {\n \"foo\": \"bar\"\n }\n}\n```\n\nAdditional information around the request such as the request context, authorizer context, and headers can be included as part of the input\nforwarded to the state machine. The following example enables headers to be included in the input but not query string.\n\n```python\napigateway.StepFunctionsRestApi(self, \"StepFunctionsRestApi\",\n state_machine=machine,\n headers=True,\n path=False,\n querystring=False,\n authorizer=False,\n request_context=apigateway.RequestContext(\n caller=True,\n user=True\n )\n)\n```\n\nIn such a case, when the endpoint is invoked as below:\n\n```bash\ncurl -X GET https://example.com/\n```\n\nAWS Step Functions will receive the following execution input:\n\n```json\n{\n \"headers\": {\n \"Accept\": \"...\",\n \"CloudFront-Forwarded-Proto\": \"...\",\n },\n \"requestContext\": {\n \"accountId\": \"...\",\n \"apiKey\": \"...\",\n },\n \"body\": {}\n}\n```\n\n### Breaking up Methods and Resources across Stacks\n\nIt is fairly common for REST APIs with a large number of Resources and Methods to hit the [CloudFormation\nlimit](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) of 500 resources per\nstack.\n\nTo help with this, Resources and Methods for the same REST API can be re-organized across multiple stacks. A common\nway to do this is to have a stack per Resource or groups of Resources, but this is not the only possible way.\nThe following example uses sets up two Resources '/pets' and '/books' in separate stacks using nested stacks:\n\n```python\nfrom aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse, IntegrationResponse, MethodResponse\nfrom aws_cdk.core import App, CfnOutput, NestedStack, NestedStackProps, Stack\nfrom constructs import Construct\nfrom aws_cdk.aws_apigateway import Deployment, Method, MockIntegration, PassthroughBehavior, RestApi, Stage\n\n#\n# This file showcases how to split up a RestApi's Resources and Methods across nested stacks.\n#\n# The root stack 'RootStack' first defines a RestApi.\n# Two nested stacks BooksStack and PetsStack, create corresponding Resources '/books' and '/pets'.\n# They are then deployed to a 'prod' Stage via a third nested stack - DeployStack.\n#\n# To verify this worked, go to the APIGateway\n#\n\nclass RootStack(Stack):\n def __init__(self, scope):\n super().__init__(scope, \"integ-restapi-import-RootStack\")\n\n rest_api = RestApi(self, \"RestApi\",\n deploy=False\n )\n rest_api.root.add_method(\"ANY\")\n\n pets_stack = PetsStack(self,\n rest_api_id=rest_api.rest_api_id,\n root_resource_id=rest_api.rest_api_root_resource_id\n )\n books_stack = BooksStack(self,\n rest_api_id=rest_api.rest_api_id,\n root_resource_id=rest_api.rest_api_root_resource_id\n )\n DeployStack(self,\n rest_api_id=rest_api.rest_api_id,\n methods=pets_stack.methods.concat(books_stack.methods)\n )\n\n CfnOutput(self, \"PetsURL\",\n value=f\"https://{restApi.restApiId}.execute-api.{this.region}.amazonaws.com/prod/pets\"\n )\n\n CfnOutput(self, \"BooksURL\",\n value=f\"https://{restApi.restApiId}.execute-api.{this.region}.amazonaws.com/prod/books\"\n )\n\nclass PetsStack(NestedStack):\n\n def __init__(self, scope, *, restApiId, rootResourceId, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):\n super().__init__(scope, \"integ-restapi-import-PetsStack\", restApiId=restApiId, rootResourceId=rootResourceId, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)\n\n api = RestApi.from_rest_api_attributes(self, \"RestApi\",\n rest_api_id=rest_api_id,\n root_resource_id=root_resource_id\n )\n\n method = api.root.add_resource(\"pets\").add_method(\"GET\", MockIntegration(\n integration_responses=[IntegrationResponse(\n status_code=\"200\"\n )],\n passthrough_behavior=PassthroughBehavior.NEVER,\n request_templates={\n \"application/json\": \"{ \\\"statusCode\\\": 200 }\"\n }\n ),\n method_responses=[MethodResponse(status_code=\"200\")]\n )\n\n self.methods.push(method)\n\nclass BooksStack(NestedStack):\n\n def __init__(self, scope, *, restApiId, rootResourceId, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):\n super().__init__(scope, \"integ-restapi-import-BooksStack\", restApiId=restApiId, rootResourceId=rootResourceId, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)\n\n api = RestApi.from_rest_api_attributes(self, \"RestApi\",\n rest_api_id=rest_api_id,\n root_resource_id=root_resource_id\n )\n\n method = api.root.add_resource(\"books\").add_method(\"GET\", MockIntegration(\n integration_responses=[IntegrationResponse(\n status_code=\"200\"\n )],\n passthrough_behavior=PassthroughBehavior.NEVER,\n request_templates={\n \"application/json\": \"{ \\\"statusCode\\\": 200 }\"\n }\n ),\n method_responses=[MethodResponse(status_code=\"200\")]\n )\n\n self.methods.push(method)\n\nclass DeployStack(NestedStack):\n def __init__(self, scope, *, restApiId, methods=None, parameters=None, timeout=None, notificationArns=None, removalPolicy=None):\n super().__init__(scope, \"integ-restapi-import-DeployStack\", restApiId=restApiId, methods=methods, parameters=parameters, timeout=timeout, notificationArns=notificationArns, removalPolicy=removalPolicy)\n\n deployment = Deployment(self, \"Deployment\",\n api=RestApi.from_rest_api_id(self, \"RestApi\", rest_api_id)\n )\n if methods:\n for method in methods:\n deployment.node.add_dependency(method)\n Stage(self, \"Stage\", deployment=deployment)\n\nRootStack(App())\n```\n\n## Integration Targets\n\nMethods are associated with backend integrations, which are invoked when this\nmethod is called. API Gateway supports the following integrations:\n\n* `MockIntegration` - can be used to test APIs. This is the default\n integration if one is not specified.\n* `LambdaIntegration` - can be used to invoke an AWS Lambda function.\n* `AwsIntegration` - can be used to invoke arbitrary AWS service APIs.\n* `HttpIntegration` - can be used to invoke HTTP endpoints.\n\nThe following example shows how to integrate the `GET /book/{book_id}` method to\nan AWS Lambda function:\n\n```python\n# get_book_handler: lambda.Function\n# book: apigateway.Resource\n\n\nget_book_integration = apigateway.LambdaIntegration(get_book_handler)\nbook.add_method(\"GET\", get_book_integration)\n```\n\nIntegration options can be optionally be specified:\n\n```python\n# get_book_handler: lambda.Function\n# get_book_integration: apigateway.LambdaIntegration\n\n\nget_book_integration = apigateway.LambdaIntegration(get_book_handler,\n content_handling=apigateway.ContentHandling.CONVERT_TO_TEXT, # convert to base64\n credentials_passthrough=True\n)\n```\n\nMethod options can optionally be specified when adding methods:\n\n```python\n# book: apigateway.Resource\n# get_book_integration: apigateway.LambdaIntegration\n\n\nbook.add_method(\"GET\", get_book_integration,\n authorization_type=apigateway.AuthorizationType.IAM,\n api_key_required=True\n)\n```\n\nIt is possible to also integrate with AWS services in a different region. The following code integrates with Amazon SQS in the\n`eu-west-1` region.\n\n```python\nget_message_integration = apigateway.AwsIntegration(\n service=\"sqs\",\n path=\"queueName\",\n region=\"eu-west-1\"\n)\n```\n\n## Usage Plan & API Keys\n\nA usage plan specifies who can access one or more deployed API stages and methods, and the rate at which they can be\naccessed. The plan uses API keys to identify API clients and meters access to the associated API stages for each key.\nUsage plans also allow configuring throttling limits and quota limits that are enforced on individual client API keys.\n\nThe following example shows how to create and asscociate a usage plan and an API key:\n\n```python\n# integration: apigateway.LambdaIntegration\n\n\napi = apigateway.RestApi(self, \"hello-api\")\n\nv1 = api.root.add_resource(\"v1\")\necho = v1.add_resource(\"echo\")\necho_method = echo.add_method(\"GET\", integration, api_key_required=True)\n\nplan = api.add_usage_plan(\"UsagePlan\",\n name=\"Easy\",\n throttle=apigateway.ThrottleSettings(\n rate_limit=10,\n burst_limit=2\n )\n)\n\nkey = api.add_api_key(\"ApiKey\")\nplan.add_api_key(key)\n```\n\nTo associate a plan to a given RestAPI stage:\n\n```python\n# plan: apigateway.UsagePlan\n# api: apigateway.RestApi\n# echo_method: apigateway.Method\n\n\nplan.add_api_stage(\n stage=api.deployment_stage,\n throttle=[apigateway.ThrottlingPerMethod(\n method=echo_method,\n throttle=apigateway.ThrottleSettings(\n rate_limit=10,\n burst_limit=2\n )\n )\n ]\n)\n```\n\nExisting usage plans can be imported into a CDK app using its id.\n\n```python\nimported_usage_plan = apigateway.UsagePlan.from_usage_plan_id(self, \"imported-usage-plan\", \"<usage-plan-key-id>\")\n```\n\nThe name and value of the API Key can be specified at creation; if not\nprovided, a name and value will be automatically generated by API Gateway.\n\n```python\n# api: apigateway.RestApi\n\nkey = api.add_api_key(\"ApiKey\",\n api_key_name=\"myApiKey1\",\n value=\"MyApiKeyThatIsAtLeast20Characters\"\n)\n```\n\nExisting API keys can also be imported into a CDK app using its id.\n\n```python\nimported_key = apigateway.ApiKey.from_api_key_id(self, \"imported-key\", \"<api-key-id>\")\n```\n\nThe \"grant\" methods can be used to give prepackaged sets of permissions to other resources. The\nfollowing code provides read permission to an API key.\n\n```python\n# imported_key: apigateway.ApiKey\n# lambda_fn: lambda.Function\n\nimported_key.grant_read(lambda_fn)\n```\n\n### \u26a0\ufe0f Multiple API Keys\n\nIt is possible to specify multiple API keys for a given Usage Plan, by calling `usagePlan.addApiKey()`.\n\nWhen using multiple API keys, a past bug of the CDK prevents API key associations to a Usage Plan to be deleted.\nIf the CDK app had the [feature flag](https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html) - `@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId` - enabled when the API\nkeys were created, then the app will not be affected by this bug.\n\nIf this is not the case, you will need to ensure that the CloudFormation [logical ids](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html) of the API keys that are not\nbeing deleted remain unchanged.\nMake note of the logical ids of these API keys before removing any, and set it as part of the `addApiKey()` method:\n\n```python\n# usageplan: apigateway.UsagePlan\n# api_key: apigateway.ApiKey\n\n\nusageplan.add_api_key(api_key,\n override_logical_id=\"...\"\n)\n```\n\n### Rate Limited API Key\n\nIn scenarios where you need to create a single api key and configure rate limiting for it, you can use `RateLimitedApiKey`.\nThis construct lets you specify rate limiting properties which should be applied only to the api key being created.\nThe API key created has the specified rate limits, such as quota and throttles, applied.\n\nThe following example shows how to use a rate limited api key :\n\n```python\n# api: apigateway.RestApi\n\n\nkey = apigateway.RateLimitedApiKey(self, \"rate-limited-api-key\",\n customer_id=\"hello-customer\",\n resources=[api],\n quota=apigateway.QuotaSettings(\n limit=10000,\n period=apigateway.Period.MONTH\n )\n)\n```\n\n## Working with models\n\nWhen you work with Lambda integrations that are not Proxy integrations, you\nhave to define your models and mappings for the request, response, and integration.\n\n```python\nhello = lambda_.Function(self, \"hello\",\n runtime=lambda_.Runtime.NODEJS_14_X,\n handler=\"hello.handler\",\n code=lambda_.Code.from_asset(\"lambda\")\n)\n\napi = apigateway.RestApi(self, \"hello-api\")\nresource = api.root.add_resource(\"v1\")\n```\n\nYou can define more parameters on the integration to tune the behavior of API Gateway\n\n```python\n# hello: lambda.Function\n\n\nintegration = apigateway.LambdaIntegration(hello,\n proxy=False,\n request_parameters={\n # You can define mapping parameters from your method to your integration\n # - Destination parameters (the key) are the integration parameters (used in mappings)\n # - Source parameters (the value) are the source request parameters or expressions\n # @see: https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html\n \"integration.request.querystring.who\": \"method.request.querystring.who\"\n },\n allow_test_invoke=True,\n request_templates={\n # You can define a mapping that will build a payload for your integration, based\n # on the integration parameters that you have specified\n # Check: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n \"application/json\": JSON.stringify({\"action\": \"sayHello\", \"poll_id\": \"$util.escapeJavaScript($input.params('who'))\"})\n },\n # This parameter defines the behavior of the engine is no suitable response template is found\n passthrough_behavior=apigateway.PassthroughBehavior.NEVER,\n integration_responses=[apigateway.IntegrationResponse(\n # Successful response from the Lambda function, no filter defined\n # - the selectionPattern filter only tests the error message\n # We will set the response status code to 200\n status_code=\"200\",\n response_templates={\n # This template takes the \"message\" result from the Lambda function, and embeds it in a JSON response\n # Check https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n \"application/json\": JSON.stringify({\"state\": \"ok\", \"greeting\": \"$util.escapeJavaScript($input.body)\"})\n },\n response_parameters={\n # We can map response parameters\n # - Destination parameters (the key) are the response parameters (used in mappings)\n # - Source parameters (the value) are the integration response parameters or expressions\n \"method.response.header.Content-Type\": \"'application/json'\",\n \"method.response.header.Access-Control-Allow-Origin\": \"'*'\",\n \"method.response.header.Access-Control-Allow-Credentials\": \"'true'\"\n }\n ), apigateway.IntegrationResponse(\n # For errors, we check if the error message is not empty, get the error data\n selection_pattern=\"(\\n|.)+\",\n # We will set the response status code to 200\n status_code=\"400\",\n response_templates={\n \"application/json\": JSON.stringify({\"state\": \"error\", \"message\": \"$util.escapeJavaScript($input.path('$.errorMessage'))\"})\n },\n response_parameters={\n \"method.response.header.Content-Type\": \"'application/json'\",\n \"method.response.header.Access-Control-Allow-Origin\": \"'*'\",\n \"method.response.header.Access-Control-Allow-Credentials\": \"'true'\"\n }\n )\n ]\n)\n```\n\nYou can define models for your responses (and requests)\n\n```python\n# api: apigateway.RestApi\n\n\n# We define the JSON Schema for the transformed valid response\nresponse_model = api.add_model(\"ResponseModel\",\n content_type=\"application/json\",\n model_name=\"ResponseModel\",\n schema=apigateway.JsonSchema(\n schema=apigateway.JsonSchemaVersion.DRAFT4,\n title=\"pollResponse\",\n type=apigateway.JsonSchemaType.OBJECT,\n properties={\n \"state\": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING),\n \"greeting\": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING)\n }\n )\n)\n\n# We define the JSON Schema for the transformed error response\nerror_response_model = api.add_model(\"ErrorResponseModel\",\n content_type=\"application/json\",\n model_name=\"ErrorResponseModel\",\n schema=apigateway.JsonSchema(\n schema=apigateway.JsonSchemaVersion.DRAFT4,\n title=\"errorResponse\",\n type=apigateway.JsonSchemaType.OBJECT,\n properties={\n \"state\": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING),\n \"message\": apigateway.JsonSchema(type=apigateway.JsonSchemaType.STRING)\n }\n )\n)\n```\n\nAnd reference all on your method definition.\n\n```python\n# integration: apigateway.LambdaIntegration\n# resource: apigateway.Resource\n# response_model: apigateway.Model\n# error_response_model: apigateway.Model\n\n\nresource.add_method(\"GET\", integration,\n # We can mark the parameters as required\n request_parameters={\n \"method.request.querystring.who\": True\n },\n # we can set request validator options like below\n request_validator_options=apigateway.RequestValidatorOptions(\n request_validator_name=\"test-validator\",\n validate_request_body=True,\n validate_request_parameters=False\n ),\n method_responses=[apigateway.MethodResponse(\n # Successful response from the integration\n status_code=\"200\",\n # Define what parameters are allowed or not\n response_parameters={\n \"method.response.header.Content-Type\": True,\n \"method.response.header.Access-Control-Allow-Origin\": True,\n \"method.response.header.Access-Control-Allow-Credentials\": True\n },\n # Validate the schema on the response\n response_models={\n \"application/json\": response_model\n }\n ), apigateway.MethodResponse(\n # Same thing for the error responses\n status_code=\"400\",\n response_parameters={\n \"method.response.header.Content-Type\": True,\n \"method.response.header.Access-Control-Allow-Origin\": True,\n \"method.response.header.Access-Control-Allow-Credentials\": True\n },\n response_models={\n \"application/json\": error_response_model\n }\n )\n ]\n)\n```\n\nSpecifying `requestValidatorOptions` automatically creates the RequestValidator construct with the given options.\nHowever, if you have your RequestValidator already initialized or imported, use the `requestValidator` option instead.\n\n## Default Integration and Method Options\n\nThe `defaultIntegration` and `defaultMethodOptions` properties can be used to\nconfigure a default integration at any resource level. These options will be\nused when defining method under this resource (recursively) with undefined\nintegration or options.\n\n> If not defined, the default integration is `MockIntegration`. See reference\n> documentation for default method options.\n\nThe following example defines the `booksBackend` integration as a default\nintegration. This means that all API methods that do not explicitly define an\nintegration will be routed to this AWS Lambda function.\n\n```python\n# books_backend: apigateway.LambdaIntegration\n\napi = apigateway.RestApi(self, \"books\",\n default_integration=books_backend\n)\n\nbooks = api.root.add_resource(\"books\")\nbooks.add_method(\"GET\") # integrated with `booksBackend`\nbooks.add_method(\"POST\") # integrated with `booksBackend`\n\nbook = books.add_resource(\"{book_id}\")\nbook.add_method(\"GET\")\n```\n\nA Method can be configured with authorization scopes. Authorization scopes are\nused in conjunction with an [authorizer that uses Amazon Cognito user\npools](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html#apigateway-enable-cognito-user-pool).\nRead more about authorization scopes\n[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html#cfn-apigateway-method-authorizationscopes).\n\nAuthorization scopes for a Method can be configured using the `authorizationScopes` property as shown below -\n\n```python\n# books: apigateway.Resource\n\n\nbooks.add_method(\"GET\", apigateway.HttpIntegration(\"http://amazon.com\"),\n authorization_type=apigateway.AuthorizationType.COGNITO,\n authorization_scopes=[\"Scope1\", \"Scope2\"]\n)\n```\n\n## Proxy Routes\n\nThe `addProxy` method can be used to install a greedy `{proxy+}` resource\non a path. By default, this also installs an `\"ANY\"` method:\n\n```python\n# resource: apigateway.Resource\n# handler: lambda.Function\n\nproxy = resource.add_proxy(\n default_integration=apigateway.LambdaIntegration(handler),\n\n # \"false\" will require explicitly adding methods on the `proxy` resource\n any_method=True\n)\n```\n\n## Authorizers\n\nAPI Gateway [supports several different authorization types](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html)\nthat can be used for controlling access to your REST APIs.\n\n### IAM-based authorizer\n\nThe following CDK code provides 'execute-api' permission to an IAM user, via IAM policies, for the 'GET' method on the `books` resource:\n\n```python\n# books: apigateway.Resource\n# iam_user: iam.User\n\n\nget_books = books.add_method(\"GET\", apigateway.HttpIntegration(\"http://amazon.com\"),\n authorization_type=apigateway.AuthorizationType.IAM\n)\n\niam_user.attach_inline_policy(iam.Policy(self, \"AllowBooks\",\n statements=[\n iam.PolicyStatement(\n actions=[\"execute-api:Invoke\"],\n effect=iam.Effect.ALLOW,\n resources=[get_books.method_arn]\n )\n ]\n))\n```\n\n### Lambda-based token authorizer\n\nAPI Gateway also allows [lambda functions to be used as authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).\n\nThis module provides support for token-based Lambda authorizers. When a client makes a request to an API's methods configured with such\nan authorizer, API Gateway calls the Lambda authorizer, which takes the caller's identity as input and returns an IAM policy as output.\nA token-based Lambda authorizer (also called a token authorizer) receives the caller's identity in a bearer token, such as\na JSON Web Token (JWT) or an OAuth token.\n\nAPI Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format.\nThe event object that the handler is called with contains the `authorizationToken` and the `methodArn` from the request to the\nAPI Gateway endpoint. The handler is expected to return the `principalId` (i.e. the client identifier) and a `policyDocument` stating\nwhat the client is authorizer to perform.\nSee [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) for a detailed specification on\ninputs and outputs of the Lambda handler.\n\nThe following code attaches a token-based Lambda authorizer to the 'GET' Method of the Book resource:\n\n```python\n# auth_fn: lambda.Function\n# books: apigateway.Resource\n\n\nauth = apigateway.TokenAuthorizer(self, \"booksAuthorizer\",\n handler=auth_fn\n)\n\nbooks.add_method(\"GET\", apigateway.HttpIntegration(\"http://amazon.com\"),\n authorizer=auth\n)\n```\n\nA full working example is shown below.\n\n!cdk-integ pragma:ignore-assets\n\n```python\nfrom aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse\nimport path as path\nimport aws_cdk.aws_lambda as lambda_\nfrom aws_cdk.core import App, Stack\nfrom aws_cdk.aws_apigateway import MockIntegration, PassthroughBehavior, RestApi, TokenAuthorizer\n\n#\n# Stack verification steps:\n# * `curl -s -o /dev/null -w \"%{http_code}\" <url>` should return 401\n# * `curl -s -o /dev/null -w \"%{http_code}\" -H 'Authorization: deny' <url>` should return 403\n# * `curl -s -o /dev/null -w \"%{http_code}\" -H 'Authorization: allow' <url>` should return 200\n#\n\napp = App()\nstack = Stack(app, \"TokenAuthorizerInteg\")\n\nauthorizer_fn = lambda_.Function(stack, \"MyAuthorizerFunction\",\n runtime=lambda_.Runtime.NODEJS_14_X,\n handler=\"index.handler\",\n code=lambda_.AssetCode.from_asset(path.join(__dirname, \"integ.token-authorizer.handler\"))\n)\n\nrestapi = RestApi(stack, \"MyRestApi\")\n\nauthorizer = TokenAuthorizer(stack, \"MyAuthorizer\",\n handler=authorizer_fn\n)\n\nrestapi.root.add_method(\"ANY\", MockIntegration(\n integration_responses=[IntegrationResponse(status_code=\"200\")\n ],\n passthrough_behavior=PassthroughBehavior.NEVER,\n request_templates={\n \"application/json\": \"{ \\\"statusCode\\\": 200 }\"\n }\n),\n method_responses=[MethodResponse(status_code=\"200\")\n ],\n authorizer=authorizer\n)\n```\n\nBy default, the `TokenAuthorizer` looks for the authorization token in the request header with the key 'Authorization'. This can,\nhowever, be modified by changing the `identitySource` property.\n\nAuthorizers can also be passed via the `defaultMethodOptions` property within the `RestApi` construct or the `Method` construct. Unless\nexplicitly overridden, the specified defaults will be applied across all `Method`s across the `RestApi` or across all `Resource`s,\ndepending on where the defaults were specified.\n\n### Lambda-based request authorizer\n\nThis module provides support for request-based Lambda authorizers. When a client makes a request to an API's methods configured with such\nan authorizer, API Gateway calls the Lambda authorizer, which takes specified parts of the request, known as identity sources,\nas input and returns an IAM policy as output. A request-based Lambda authorizer (also called a request authorizer) receives\nthe identity sources in a series of values pulled from the request, from the headers, stage variables, query strings, and the context.\n\nAPI Gateway interacts with the authorizer Lambda function handler by passing input and expecting the output in a specific format.\nThe event object that the handler is called with contains the body of the request and the `methodArn` from the request to the\nAPI Gateway endpoint. The handler is expected to return the `principalId` (i.e. the client identifier) and a `policyDocument` stating\nwhat the client is authorizer to perform.\nSee [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) for a detailed specification on\ninputs and outputs of the Lambda handler.\n\nThe following code attaches a request-based Lambda authorizer to the 'GET' Method of the Book resource:\n\n```python\n# auth_fn: lambda.Function\n# books: apigateway.Resource\n\n\nauth = apigateway.RequestAuthorizer(self, \"booksAuthorizer\",\n handler=auth_fn,\n identity_sources=[apigateway.IdentitySource.header(\"Authorization\")]\n)\n\nbooks.add_method(\"GET\", apigateway.HttpIntegration(\"http://amazon.com\"),\n authorizer=auth\n)\n```\n\nA full working example is shown below.\n\n!cdk-integ pragma:ignore-assets\n\n```python\nfrom aws_cdk.aws_apigateway import IntegrationResponse, MethodResponse\nimport path as path\nimport aws_cdk.aws_lambda as lambda_\nfrom aws_cdk.core import App, Stack\nfrom aws_cdk.aws_apigateway import MockIntegration, PassthroughBehavior, RestApi\nfrom aws_cdk.aws_apigateway import RequestAuthorizer\nfrom aws_cdk.aws_apigateway import IdentitySource\n\n# Against the RestApi endpoint from the stack output, run\n# `curl -s -o /dev/null -w \"%{http_code}\" <url>` should return 401\n# `curl -s -o /dev/null -w \"%{http_code}\" -H 'Authorization: deny' <url>?allow=yes` should return 403\n# `curl -s -o /dev/null -w \"%{http_code}\" -H 'Authorization: allow' <url>?allow=yes` should return 200\n\napp = App()\nstack = Stack(app, \"RequestAuthorizerInteg\")\n\nauthorizer_fn = lambda_.Function(stack, \"MyAuthorizerFunction\",\n runtime=lambda_.Runtime.NODEJS_14_X,\n handler=\"index.handler\",\n code=lambda_.AssetCode.from_asset(path.join(__dirname, \"integ.request-authorizer.handler\"))\n)\n\nrestapi = RestApi(stack, \"MyRestApi\")\n\nauthorizer = RequestAuthorizer(stack, \"MyAuthorizer\",\n handler=authorizer_fn,\n identity_sources=[IdentitySource.header(\"Authorization\"), IdentitySource.query_string(\"allow\")]\n)\n\nrestapi.root.add_method(\"ANY\", MockIntegration(\n integration_responses=[IntegrationResponse(status_code=\"200\")\n ],\n passthrough_behavior=PassthroughBehavior.NEVER,\n request_templates={\n \"application/json\": \"{ \\\"statusCode\\\": 200 }\"\n }\n),\n method_responses=[MethodResponse(status_code=\"200\")\n ],\n authorizer=authorizer\n)\n```\n\nBy default, the `RequestAuthorizer` does not pass any kind of information from the request. This can,\nhowever, be modified by changing the `identitySource` property, and is required when specifying a value for caching.\n\nAuthorizers can also be passed via the `defaultMethodOptions` property within the `RestApi` construct or the `Method` construct. Unless\nexplicitly overridden, the specified defaults will be applied across all `Method`s across the `RestApi` or across all `Resource`s,\ndepending on where the defaults were specified.\n\n### Cognito User Pools authorizer\n\nAPI Gateway also allows [Amazon Cognito user pools as authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html)\n\nThe following snippet configures a Cognito user pool as an authorizer:\n\n```python\n# books: apigateway.Resource\nuser_pool = cognito.UserPool(self, \"UserPool\")\n\nauth = apigateway.CognitoUserPoolsAuthorizer(self, \"booksAuthorizer\",\n cognito_user_pools=[user_pool]\n)\nbooks.add_method(\"GET\", apigateway.HttpIntegration(\"http://amazon.com\"),\n authorizer=auth,\n authorization_type=apigateway.AuthorizationType.COGNITO\n)\n```\n\n## Mutual TLS (mTLS)\n\nMutual TLS can be configured to limit access to your API based by using client certificates instead of (or as an extension of) using authorization headers.\n\n```python\n# acm: Any\n\n\napigateway.DomainName(self, \"domain-name\",\n domain_name=\"example.com\",\n certificate=acm.Certificate.from_certificate_arn(self, \"cert\", \"arn:aws:acm:us-east-1:1111111:certificate/11-3336f1-44483d-adc7-9cd375c5169d\"),\n mtls=apigateway.MTLSConfig(\n bucket=s3.Bucket(self, \"bucket\"),\n key=\"truststore.pem\",\n version=\"version\"\n )\n)\n```\n\nInstructions for configuring your trust store can be found [here](https://aws.amazon.com/blogs/compute/introducing-mutual-tls-authentication-for-amazon-api-gateway/).\n\n## Deployments\n\nBy default, the `RestApi` construct will automatically create an API Gateway\n[Deployment](https://docs.aws.amazon.com/apigateway/api-reference/resource/deployment/) and a \"prod\" [Stage](https://docs.aws.amazon.com/apigateway/api-reference/resource/stage/) which represent the API configuration you\ndefined in your CDK app. This means that when you deploy your app, your API will\nbe have open access from the internet via the stage URL.\n\nThe URL of your API can be obtained from the attribute `restApi.url`, and is\nalso exported as an `Output` from your stack, so it's printed when you `cdk deploy` your app:\n\n```console\n$ cdk deploy\n...\nbooks.booksapiEndpointE230E8D5 = https://6lyktd4lpk.execute-api.us-east-1.amazonaws.com/prod/\n```\n\nTo disable this behavior, you can set `{ deploy: false }` when creating your\nAPI. This means that the API will not be deployed and a stage will not be\ncreated for it. You will need to manually define a `apigateway.Deployment` and\n`apigateway.Stage` resources.\n\nUse the `deployOptions` property to customize the deployment options of your\nAPI.\n\nThe following example will configure API Gateway to emit logs and data traces to\nAWS CloudWatch for all API calls:\n\n> By default, an IAM role will be created and associated with API Gateway to\n> allow it to write logs and metrics to AWS CloudWatch unless `cloudWatchRole` is\n> set to `false`.\n\n```python\napi = apigateway.RestApi(self, \"books\",\n deploy_options=apigateway.StageOptions(\n logging_level=apigateway.MethodLoggingLevel.INFO,\n data_trace_enabled=True\n )\n)\n```\n\n### Deep dive: Invalidation of deployments\n\nAPI Gateway deployments are an immutable snapshot of the API. This means that we\nwant to automatically create a new deployment resource every time the API model\ndefined in our CDK app changes.\n\nIn order to achieve that, the AWS CloudFormation logical ID of the\n`AWS::ApiGateway::Deployment` resource is dynamically calculated by hashing the\nAPI configuration (resources, methods). This means that when the configuration\nchanges (i.e. a resource or method are added, configuration is changed), a new\nlogical ID will be assigned to the deployment resource. This will cause\nCloudFormation to create a new deployment resource.\n\nBy default, old deployments are *deleted*. You can set `retainDeployments: true`\nto allow users revert the stage to an old deployment manually.\n\n## Custom Domains\n\nTo associate an API with a custom domain, use the `domainName` configuration when\nyou define your API:\n\n```python\n# acm_certificate_for_example_com: Any\n\n\napi = apigateway.RestApi(self, \"MyDomain\",\n domain_name=apigateway.DomainNameOptions(\n domain_name=\"example.com\",\n certificate=acm_certificate_for_example_com\n )\n)\n```\n\nThis will define a `DomainName` resource for you, along with a `BasePathMapping`\nfrom the root of the domain to the deployment stage of the API. This is a common\nset up.\n\nTo route domain traffic to an API Gateway API, use Amazon Route 53 to create an\nalias record. An alias record is a Route 53 extension to DNS. It's similar to a\nCNAME record, but you can create an alias record both for the root domain, such\nas `example.com`, and for subdomains, such as `www.example.com`. (You can create\nCNAME records only for subdomains.)\n\n```python\nimport aws_cdk.aws_route53 as route53\nimport aws_cdk.aws_route53_targets as targets\n\n# api: apigateway.RestApi\n# hosted_zone_for_example_com: Any\n\n\nroute53.ARecord(self, \"CustomDomainAliasRecord\",\n zone=hosted_zone_for_example_com,\n target=route53.RecordTarget.from_alias(targets.ApiGateway(api))\n)\n```\n\nYou can also define a `DomainName` resource directly in order to customize the default behavior:\n\n```python\n# acm_certificate_for_example_com: Any\n\n\napigateway.DomainName(self, \"custom-domain\",\n domain_name=\"example.com\",\n certificate=acm_certificate_for_example_com,\n endpoint_type=apigateway.EndpointType.EDGE, # default is REGIONAL\n security_policy=apigateway.SecurityPolicy.TLS_1_2\n)\n```\n\nOnce you have a domain, you can map base paths of the domain to APIs.\nThe following example will map the URL [https://example.com/go-to-api1](https://example.com/go-to-api1)\nto the `api1` API and [https://example.com/boom](https://example.com/boom) to the `api2` API.\n\n```python\n# domain: apigateway.DomainName\n# api1: apigateway.RestApi\n# api2: apigateway.RestApi\n\n\ndomain.add_base_path_mapping(api1, base_path=\"go-to-api1\")\ndomain.add_base_path_mapping(api2, base_path=\"boom\")\n```\n\nYou can specify the API `Stage` to which this base path URL will map to. By default, this will be the\n`deploymentStage` of the `RestApi`.\n\n```python\n# domain: apigateway.DomainName\n# restapi: apigateway.RestApi\n\n\nbeta_deploy = apigateway.Deployment(self, \"beta-deployment\",\n api=restapi\n)\nbeta_stage = apigateway.Stage(self, \"beta-stage\",\n deployment=beta_deploy\n)\ndomain.add_base_path_mapping(restapi, base_path=\"api/beta\", stage=beta_stage)\n```\n\nIf you don't specify `basePath`, all URLs under this domain will be mapped\nto the API, and you won't be able to map another API to the same domain:\n\n```python\n# domain: apigateway.DomainName\n# api: apigateway.RestApi\n\ndomain.add_base_path_mapping(api)\n```\n\nThis can also be achieved through the `mapping` configuration when defining the\ndomain as demonstrated above.\n\nIf you wish to setup this domain with an Amazon Route53 alias, use the `targets.ApiGatewayDomain`:\n\n```python\n# hosted_zone_for_example_com: Any\n# domain_name: apigateway.DomainName\n\nimport aws_cdk.aws_route53 as route53\nimport aws_cdk.aws_route53_targets as targets\n\n\nroute53.ARecord(self, \"CustomDomainAliasRecord\",\n zone=hosted_zone_for_example_com,\n target=route53.RecordTarget.from_alias(targets.ApiGatewayDomain(domain_name))\n)\n```\n\n## Access Logging\n\nAccess logging creates logs every time an API method is accessed. Access logs can have information on\nwho has accessed the API, how the caller accessed the API and what responses were generated.\nAccess logs are configured on a Stage of the RestApi.\nAccess logs can be expressed in a format of your choosing, and can contain any access details, with a\nminimum that it must include the 'requestId'. The list of variables that can be expressed in the access\nlog can be found\n[here](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference).\nRead more at [Setting Up CloudWatch API Logging in API\nGateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html)\n\n```python\n# production stage\nprd_log_group = logs.LogGroup(self, \"PrdLogs\")\napi = apigateway.RestApi(self, \"books\",\n deploy_options=apigateway.StageOptions(\n access_log_destination=apigateway.LogGroupLogDestination(prd_log_group),\n access_log_format=apigateway.AccessLogFormat.json_with_standard_fields()\n )\n)\ndeployment = apigateway.Deployment(self, \"Deployment\", api=api)\n\n# development stage\ndev_log_group = logs.LogGroup(self, \"DevLogs\")\napigateway.Stage(self, \"dev\",\n deployment=deployment,\n access_log_destination=apigateway.LogGroupLogDestination(dev_log_group),\n access_log_format=apigateway.AccessLogFormat.json_with_standard_fields(\n caller=False,\n http_method=True,\n ip=True,\n protocol=True,\n request_time=True,\n resource_path=True,\n response_length=True,\n status=True,\n user=True\n )\n)\n```\n\nThe following code will generate the access log in the [CLF format](https://en.wikipedia.org/wiki/Common_Log_Format).\n\n```python\nlog_group = logs.LogGroup(self, \"ApiGatewayAccessLogs\")\napi = apigateway.RestApi(self, \"books\",\n deploy_options=apigateway.StageOptions(\n access_log_destination=apigateway.LogGroupLogDestination(log_group),\n access_log_format=apigateway.AccessLogFormat.clf()\n )\n)\n```\n\nYou can also configure your own access log format by using the `AccessLogFormat.custom()` API.\n`AccessLogField` provides commonly used fields. The following code configures access log to contain.\n\n```python\nlog_group = logs.LogGroup(self, \"ApiGatewayAccessLogs\")\napigateway.RestApi(self, \"books\",\n deploy_options=apigateway.StageOptions(\n access_log_destination=apigateway.LogGroupLogDestination(log_group),\n access_log_format=apigateway.AccessLogFormat.custom(f\"{apigateway.AccessLogField.contextRequestId()} {apigateway.AccessLogField.contextErrorMessage()} {apigateway.AccessLogField.contextErrorMessageString()}\")\n )\n)\n```\n\nYou can use the `methodOptions` property to configure\n[default method throttling](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html#apigateway-api-level-throttling-in-usage-plan)\nfor a stage. The following snippet configures the a stage that accepts\n100 requests per minute, allowing burst up to 200 requests per minute.\n\n```python\napi = apigateway.RestApi(self, \"books\")\ndeployment = apigateway.Deployment(self, \"my-deployment\", api=api)\nstage = apigateway.Stage(self, \"my-stage\",\n deployment=deployment,\n method_options={\n \"/*/*\": apigateway.MethodDeploymentOptions( # This special path applies to all resource paths and all HTTP methods\n throttling_rate_limit=100,\n throttling_burst_limit=200)\n }\n)\n```\n\nConfiguring `methodOptions` on the `deployOptions` of `RestApi` will set the\nthrottling behaviors on the default stage that is automatically created.\n\n```python\napi = apigateway.RestApi(self, \"books\",\n deploy_options=apigateway.StageOptions(\n method_options={\n \"/*/*\": apigateway.MethodDeploymentOptions( # This special path applies to all resource paths and all HTTP methods\n throttling_rate_limit=100,\n throttling_burst_limit=1000)\n }\n )\n)\n```\n\n## Cross Origin Resource Sharing (CORS)\n\n[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a mechanism\nthat uses additional HTTP headers to tell browsers to give a web application\nrunning at one origin, access to selected resources from a different origin. A\nweb application executes a cross-origin HTTP request when it requests a resource\nthat has a different origin (domain, protocol, or port) from its own.\n\nYou can add the CORS [preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests) OPTIONS\nHTTP method to any API resource via the `defaultCorsPreflightOptions` option or by calling the `addCorsPreflight` on a specific resource.\n\nThe following example will enable CORS for all methods and all origins on all resources of the API:\n\n```python\napigateway.RestApi(self, \"api\",\n default_cors_preflight_options=apigateway.CorsOptions(\n allow_origins=apigateway.Cors.ALL_ORIGINS,\n allow_methods=apigateway.Cors.ALL_METHODS\n )\n)\n```\n\nThe following example will add an OPTIONS method to the `myResource` API resource, which\nonly allows GET and PUT HTTP requests from the origin [https://amazon.com.](https://amazon.com.)\n\n```python\n# my_resource: apigateway.Resource\n\n\nmy_resource.add_cors_preflight(\n allow_origins=[\"https://amazon.com\"],\n allow_methods=[\"GET\", \"PUT\"]\n)\n```\n\nSee the\n[`CorsOptions`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.CorsOptions.html)\nAPI reference for a detailed list of supported configuration options.\n\nYou can specify defaults this at the resource level, in which case they will be applied to the entire resource sub-tree:\n\n```python\n# resource: apigateway.Resource\n\n\nsubtree = resource.add_resource(\"subtree\",\n default_cors_preflight_options=apigateway.CorsOptions(\n allow_origins=[\"https://amazon.com\"]\n )\n)\n```\n\nThis means that all resources under `subtree` (inclusive) will have a preflight\nOPTIONS added to them.\n\nSee [#906](https://github.com/aws/aws-cdk/issues/906) for a list of CORS\nfeatures which are not yet supported.\n\n## Endpoint Configuration\n\nAPI gateway allows you to specify an\n[API Endpoint Type](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html).\nTo define an endpoint type for the API gateway, use `endpointConfiguration` property:\n\n```python\napi = apigateway.RestApi(self, \"api\",\n endpoint_configuration=apigateway.EndpointConfiguration(\n types=[apigateway.EndpointType.EDGE]\n )\n)\n```\n\nYou can also create an association between your Rest API and a VPC endpoint. By doing so,\nAPI Gateway will generate a new\nRoute53 Alias DNS record which you can use to invoke your private APIs. More info can be found\n[here](https://docs.aws.amazon.com/apigateway/latest/developerguide/associate-private-api-with-vpc-endpoint.html).\n\nHere is an example:\n\n```python\n# some_endpoint: ec2.IVpcEndpoint\n\n\napi = apigateway.RestApi(self, \"api\",\n endpoint_configuration=apigateway.EndpointConfiguration(\n types=[apigateway.EndpointType.PRIVATE],\n vpc_endpoints=[some_endpoint]\n )\n)\n```\n\nBy performing this association, we can invoke the API gateway using the following format:\n\n```plaintext\nhttps://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}\n```\n\n## Private Integrations\n\nA private integration makes it simple to expose HTTP/HTTPS resources behind an\nAmazon VPC for access by clients outside of the VPC. The private integration uses\nan API Gateway resource of `VpcLink` to encapsulate connections between API\nGateway and targeted VPC resources.\nThe `VpcLink` is then attached to the `Integration` of a specific API Gateway\nMethod. The following code sets up a private integration with a network load\nbalancer -\n\n```python\nimport aws_cdk.aws_elasticloadbalancingv2 as elbv2\n\n\nvpc = ec2.Vpc(self, \"VPC\")\nnlb = elbv2.NetworkLoadBalancer(self, \"NLB\",\n vpc=vpc\n)\nlink = apigateway.VpcLink(self, \"link\",\n targets=[nlb]\n)\n\nintegration = apigateway.Integration(\n type=apigateway.IntegrationType.HTTP_PROXY,\n options=apigateway.IntegrationOptions(\n connection_type=apigateway.ConnectionType.VPC_LINK,\n vpc_link=link\n )\n)\n```\n\nThe uri for the private integration, in the case of a VpcLink, will be set to the DNS name of\nthe VPC Link's NLB. If the VPC Link has multiple NLBs or the VPC Link is imported or the DNS\nname cannot be determined for any other reason, the user is expected to specify the `uri`\nproperty.\n\nAny existing `VpcLink` resource can be imported into the CDK app via the `VpcLink.fromVpcLinkId()`.\n\n```python\nawesome_link = apigateway.VpcLink.from_vpc_link_id(self, \"awesome-vpc-link\", \"us-east-1_oiuR12Abd\")\n```\n\n## Gateway response\n\nIf the Rest API fails to process an incoming request, it returns to the client an error response without forwarding the\nrequest to the integration backend. API Gateway has a set of standard response messages that are sent to the client for\neach type of error. These error responses can be configured on the Rest API. The list of Gateway responses that can be\nconfigured can be found [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html).\nLearn more about [Gateway\nResponses](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html).\n\nThe following code configures a Gateway Response when the response is 'access denied':\n\n```python\napi = apigateway.RestApi(self, \"books-api\")\napi.add_gateway_response(\"test-response\",\n type=apigateway.ResponseType.ACCESS_DENIED,\n status_code=\"500\",\n response_headers={\n \"Access-Control-Allow-Origin\": \"test.com\",\n \"test-key\": \"test-value\"\n },\n templates={\n \"application/json\": \"{ \\\"message\\\": $context.error.messageString, \\\"statusCode\\\": \\\"488\\\", \\\"type\\\": \\\"$context.error.responseType\\\" }\"\n }\n)\n```\n\n## OpenAPI Definition\n\nCDK supports creating a REST API by importing an OpenAPI definition file. It currently supports OpenAPI v2.0 and OpenAPI\nv3.0 definition files. Read more about [Configuring a REST API using\nOpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html).\n\nThe following code creates a REST API using an external OpenAPI definition JSON file -\n\n```python\n# integration: apigateway.Integration\n\n\napi = apigateway.SpecRestApi(self, \"books-api\",\n api_definition=apigateway.ApiDefinition.from_asset(\"path-to-file.json\")\n)\n\nbooks_resource = api.root.add_resource(\"books\")\nbooks_resource.add_method(\"GET\", integration)\n```\n\nIt is possible to use the `addResource()` API to define additional API Gateway Resources.\n\n**Note:** Deployment will fail if a Resource of the same name is already defined in the Open API specification.\n\n**Note:** Any default properties configured, such as `defaultIntegration`, `defaultMethodOptions`, etc. will only be\napplied to Resources and Methods defined in the CDK, and not the ones defined in the spec. Use the [API Gateway\nextensions to OpenAPI](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html)\nto configure these.\n\nThere are a number of limitations in using OpenAPI definitions in API Gateway. Read the [Amazon API Gateway important\nnotes for REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html#api-gateway-known-issues-rest-apis)\nfor more details.\n\n**Note:** When starting off with an OpenAPI definition using `SpecRestApi`, it is not possible to configure some\nproperties that can be configured directly in the OpenAPI specification file. This is to prevent people duplication\nof these properties and potential confusion.\n\n### Endpoint configuration\n\nBy default, `SpecRestApi` will create an edge optimized endpoint.\n\nThis can be modified as shown below:\n\n```python\n# api_definition: apigateway.ApiDefinition\n\n\napi = apigateway.SpecRestApi(self, \"ExampleRestApi\",\n api_definition=api_definition,\n endpoint_types=[apigateway.EndpointType.PRIVATE]\n)\n```\n\n**Note:** For private endpoints you will still need to provide the\n[`x-amazon-apigateway-policy`](https://docs.aws.amazon.com/apigateway/latest/developerguide/openapi-extensions-policy.html) and\n[`x-amazon-apigateway-endpoint-configuration`](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)\nin your openApi file.\n\n## Metrics\n\nThe API Gateway service sends metrics around the performance of Rest APIs to Amazon CloudWatch.\nThese metrics can be referred to using the metric APIs available on the `RestApi` construct.\nThe APIs with the `metric` prefix can be used to get reference to specific metrics for this API. For example,\nthe method below refers to the client side errors metric for this API.\n\n```python\napi = apigateway.RestApi(self, \"my-api\")\nclient_error_metric = api.metric_client_error()\n```\n\n## APIGateway v2\n\nAPIGateway v2 APIs are now moved to its own package named `aws-apigatewayv2`. For backwards compatibility, existing\nAPIGateway v2 \"CFN resources\" (such as `CfnApi`) that were previously exported as part of this package, are still\nexported from here and have been marked deprecated. However, updates to these CloudFormation resources, such as new\nproperties and new resource types will not be available.\n\nMove to using `aws-apigatewayv2` to get the latest APIs and updates.\n\n---\n\n\nThis module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.\n\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "The CDK Construct Library for AWS::ApiGateway",
"version": "1.203.0",
"project_urls": {
"Homepage": "https://github.com/aws/aws-cdk",
"Source": "https://github.com/aws/aws-cdk.git"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "b33fb41bdf9d63d7f1983206844715a69f5e3a845a49ce2e9859eb7ebdfc2cbb",
"md5": "09b7463a05f87075d79c8be7e2e665fe",
"sha256": "73591336ca0cd650770a3ee68f29249604a964b1fdc080713fd3965a14887da7"
},
"downloads": -1,
"filename": "aws_cdk.aws_apigateway-1.203.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "09b7463a05f87075d79c8be7e2e665fe",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "~=3.7",
"size": 975474,
"upload_time": "2023-05-31T22:52:26",
"upload_time_iso_8601": "2023-05-31T22:52:26.340048Z",
"url": "https://files.pythonhosted.org/packages/b3/3f/b41bdf9d63d7f1983206844715a69f5e3a845a49ce2e9859eb7ebdfc2cbb/aws_cdk.aws_apigateway-1.203.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "401c91d12d887e8e46e2794d02c66b0c41cc577afabc2005d97d91b475c57b50",
"md5": "80436ec75a9eb5eae09550fdf917e3f3",
"sha256": "e92b77311a9ba842d930fe490a11641f212a7df4d85ed7d996effe47bd80cde2"
},
"downloads": -1,
"filename": "aws-cdk.aws-apigateway-1.203.0.tar.gz",
"has_sig": false,
"md5_digest": "80436ec75a9eb5eae09550fdf917e3f3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "~=3.7",
"size": 1002030,
"upload_time": "2023-05-31T23:00:27",
"upload_time_iso_8601": "2023-05-31T23:00:27.468975Z",
"url": "https://files.pythonhosted.org/packages/40/1c/91d12d887e8e46e2794d02c66b0c41cc577afabc2005d97d91b475c57b50/aws-cdk.aws-apigateway-1.203.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-05-31 23:00:27",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "aws",
"github_project": "aws-cdk",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "aws-cdk.aws-apigateway"
}