-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(apigateway): step functions integration #16827
Changes from 33 commits
014e130
23b6fd7
819468f
128a4fa
a28fdab
b4c5b53
f8f332f
50680d5
a6b8165
10e361f
151ead7
7e416ef
ab86c7e
5306f22
16ef951
d0fe918
fff8835
663ece7
3bf2c8b
7d950b1
2f10576
dc3b54f
8ebf0c7
de43130
2cc14dc
d2ad11d
1ca20ea
e4b9ff5
ede456f
c8b1630
8aaf67a
e501659
9a95f46
884397e
0bf4637
2623b65
57763b8
0ff219a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -22,6 +22,7 @@ running on AWS Lambda, or any web application. | |||||||||||||||
- [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) | ||||||||||||||||
|
@@ -106,6 +107,128 @@ item.addMethod('GET'); // GET /items/{item} | |||||||||||||||
item.addMethod('DELETE', new 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` and `querystring` 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: | ||||||||||||||||
|
||||||||||||||||
```ts | ||||||||||||||||
const stateMachineDefinition = new stepfunctions.Pass(this, 'PassState'); | ||||||||||||||||
|
||||||||||||||||
const stateMachine: stepfunctions.IStateMachine = new stepfunctions.StateMachine(this, 'StateMachine', { | ||||||||||||||||
definition: stateMachineDefinition, | ||||||||||||||||
stateMachineType: stepfunctions.StateMachineType.EXPRESS, | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { | ||||||||||||||||
deploy: true, | ||||||||||||||||
stateMachine: stateMachine, | ||||||||||||||||
}); | ||||||||||||||||
``` | ||||||||||||||||
|
||||||||||||||||
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 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. | ||||||||||||||||
|
||||||||||||||||
```ts | ||||||||||||||||
const stateMachineDefinition = new stepfunctions.Pass(this, 'PassState'); | ||||||||||||||||
|
||||||||||||||||
const stateMachine: stepfunctions.IStateMachine = new stepfunctions.StateMachine(this, 'StateMachine', { | ||||||||||||||||
definition: stateMachineDefinition, | ||||||||||||||||
stateMachineType: stepfunctions.StateMachineType.EXPRESS, | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (minor) no need to repeat this again. Just focus on the code that is changing.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've pushed a commit that fixes this up. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you! |
||||||||||||||||
new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', { | ||||||||||||||||
stateMachine: stateMachine, | ||||||||||||||||
headers: true, | ||||||||||||||||
path: false, | ||||||||||||||||
querystring: false, | ||||||||||||||||
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 | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/** | ||
* Configure what must be included in the `requestContext` | ||
* | ||
* More details can be found at mapping templates documentation. | ||
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html | ||
*/ | ||
export interface RequestContext { | ||
/** | ||
* Represents the information of $context.identity.accountId | ||
* | ||
* Whether the AWS account of the API owner should be included in the request context | ||
* @default false | ||
*/ | ||
readonly accountId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.apiId | ||
* | ||
* Whether the identifier API Gateway assigns to your API should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly apiId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.apiKey | ||
* | ||
* Whether the API key associated with the request should be included in request context. | ||
* @default false | ||
*/ | ||
readonly apiKey?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.authorizer.principalId | ||
* | ||
* Whether the principal user identifier associated with the token sent by the client and returned | ||
* from an API Gateway Lambda authorizer should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly authorizerPrincipalId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.caller | ||
* | ||
* Whether the principal identifier of the caller that signed the request should be included in the request context. | ||
* Supported for resources that use IAM authorization. | ||
* @default false | ||
*/ | ||
readonly caller?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.cognitoAuthenticationProvider | ||
* | ||
* Whether the list of the Amazon Cognito authentication providers used by the caller making the request should be included in the request context. | ||
* Available only if the request was signed with Amazon Cognito credentials. | ||
* @default false | ||
*/ | ||
readonly cognitoAuthenticationProvider?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.cognitoAuthenticationType | ||
* | ||
* Whether the Amazon Cognito authentication type of the caller making the request should be included in the request context. | ||
* Available only if the request was signed with Amazon Cognito credentials. | ||
* Possible values include authenticated for authenticated identities and unauthenticated for unauthenticated identities. | ||
* @default false | ||
*/ | ||
readonly cognitoAuthenticationType?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.cognitoIdentityId | ||
* | ||
* Whether the Amazon Cognito identity ID of the caller making the request should be included in the request context. | ||
* Available only if the request was signed with Amazon Cognito credentials. | ||
* @default false | ||
*/ | ||
readonly cognitoIdentityId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.cognitoIdentityPoolId | ||
* | ||
* Whether the Amazon Cognito identity pool ID of the caller making the request should be included in the request context. | ||
* Available only if the request was signed with Amazon Cognito credentials. | ||
* @default false | ||
*/ | ||
readonly cognitoIdentityPoolId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.httpMethod | ||
* | ||
* Whether the HTTP method used should be included in the request context. | ||
* Valid values include: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT. | ||
* @default false | ||
*/ | ||
readonly httpMethod?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.stage | ||
* | ||
* Whether the deployment stage of the API request should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly stage?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.sourceIp | ||
* | ||
* Whether the source IP address of the immediate TCP connection making the request | ||
* to API Gateway endpoint should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly sourceIp?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.user | ||
* | ||
* Whether the principal identifier of the user that will be authorized should be included in the request context. | ||
* Supported for resources that use IAM authorization. | ||
* @default false | ||
*/ | ||
readonly user?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.userAgent | ||
* | ||
* Whether the User-Agent header of the API caller should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly userAgent?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.identity.userArn | ||
* | ||
* Whether the Amazon Resource Name (ARN) of the effective user identified after authentication should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly userArn?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.requestId | ||
* | ||
* Whether the ID for the request should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly requestId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.resourceId | ||
* | ||
* Whether the identifier that API Gateway assigns to your resource should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly resourceId?: boolean; | ||
|
||
/** | ||
* Represents the information of $context.resourcePath | ||
* | ||
* Whether the path to the resource should be included in the request context. | ||
* @default false | ||
*/ | ||
readonly resourcePath?: boolean; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing! I've approved the PR and it is now merged.