Skip to content

Commit

Permalink
feat(apigateway): step functions integration (aws#16827)
Browse files Browse the repository at this point in the history
- Added StepFunctionsRestApi and StepFunctionsIntegration implementation

closes aws#15081.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
saqibdhuka authored and TikiTDO committed Feb 21, 2022
1 parent 93e5a53 commit 101531f
Show file tree
Hide file tree
Showing 17 changed files with 1,800 additions and 0 deletions.
116 changes: 116 additions & 0 deletions packages/@aws-cdk/aws-apigateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -106,6 +107,121 @@ 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 fixture=stepfunctions
new apigateway.StepFunctionsRestApi(this, 'StepFunctionsRestApi', {
stateMachine: machine,
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
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-apigateway/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './authorizers';
export * from './access-log';
export * from './api-definition';
export * from './gateway-response';
export * from './stepfunctions-api';

// AWS::ApiGateway CloudFormation Resources:
export * from './apigateway.generated';
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/integrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from './aws';
export * from './lambda';
export * from './http';
export * from './mock';
export * from './stepfunctions';
export * from './request-context';
161 changes: 161 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/integrations/request-context.ts
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;
}
Loading

0 comments on commit 101531f

Please sign in to comment.