Skip to content
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(apigatewayv2-integrations): EventBridge PutEvents integration #13017

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0079639
Related to: #11947
shankben Feb 19, 2021
a365938
mistake from resolving conflict
shankben Feb 19, 2021
56bf30e
Merge remote-tracking branch 'upstream/master' into shankben/aws-prox…
shankben Feb 19, 2021
875aac7
Merge remote-tracking branch 'upstream/master' into shankben/aws-prox…
shankben Feb 23, 2021
624347a
Update packages/@aws-cdk/aws-apigatewayv2-integrations/README.md
shankben Feb 23, 2021
4a9ff6c
Merge branch 'shankben/aws-proxy-apigateway2-integration' of github.c…
shankben Feb 23, 2021
c47d775
update TOC
shankben Feb 23, 2021
87334b5
Update packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/event…
shankben Feb 23, 2021
7572fad
Merge branch 'shankben/aws-proxy-apigateway2-integration' of github.c…
shankben Feb 23, 2021
8b654b4
rm empty type AwsServiceIntegrationOptions
shankben Feb 23, 2021
7f163c4
Update packages/@aws-cdk/aws-apigatewayv2-integrations/lib/http/event…
shankben Feb 23, 2021
17bf676
Merge branch 'shankben/aws-proxy-apigateway2-integration' of github.c…
shankben Feb 23, 2021
ac3721d
rm AwsServiceIntegrationRequestParameters type alias
shankben Feb 23, 2021
b817240
move internal class to private/integration.ts
shankben Feb 23, 2021
2d4d363
specify defaults
shankben Feb 23, 2021
66cf35f
reflow to 120
shankben Feb 23, 2021
440187d
spelling
shankben Feb 23, 2021
a88c5be
mv EventBridgeIntegrationRequestParameters into eventbridge.ts; redef…
shankben Feb 25, 2021
87e49fb
verbiage
shankben Feb 25, 2021
81912fb
at the L2 level, eventBus will always supply the eventBusName request…
shankben Feb 25, 2021
f4d1fd8
update README
shankben Feb 25, 2021
4bded77
so shall it be
shankben Feb 25, 2021
1ed9d20
define specific type for EventBridge target action, rather than using…
shankben Feb 25, 2021
f7a4dc5
less words
shankben Feb 25, 2021
494e981
Merge branch 'master' into shankben/aws-proxy-apigateway2-integration
shankben Mar 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion packages/@aws-cdk/aws-apigatewayv2-integrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,50 @@
## Table of Contents

- [HTTP APIs](#http-apis)
- [Amazon EventBridge](#amazon-eventbridge)
- [Lambda Integration](#lambda)
- [HTTP Proxy Integration](#http-proxy)
- [Private Integration](#private-integration)

## HTTP APIs

Integrations connect a route to backend resources. HTTP APIs support Lambda proxy, AWS service, and HTTP proxy integrations. HTTP proxy integrations are also known as private integrations.
Integrations connect a route to backend resources. HTTP APIs support Lambda proxy, AWS service, and HTTP proxy
integrations. HTTP proxy integrations are also known as private integrations.

### Amazon EventBridge
shankben marked this conversation as resolved.
Show resolved Hide resolved

You can directly integrate the EventBridge PutEvents API into a route of your HTTP API. The integration expects a set of
`requestParameters` as part of the configuration, which can be referenced from the [Integration Subtype
Reference](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-aws-services-reference.html#EventBridge-PutEvents).

The following code configures a default HTTP API integration with the EventBridge service's PutEvents API call. Note you
can map parameters from HTTP API first-class integrations like EventBridge PutEvents like `$request` and `$context` as
demonstrated below. For further reference, see the list of [supported request
parameters](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-aws-services.html).

```ts
import * as events from '@aws-cdk/aws-events';

const eventBus = new events.EventBus(stack, 'EventBus');
const eventBridgeIntegration = new EventBridgeIntegration({
eventBus,
requestParameters: {
source: 'test',
detail: '$request.body.result',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this needs to be a valid JSON string, no?

detailType: '$request.body.description',
time: '$context.requestTimeEpoch',
}
});

const httpApi = new HttpApi(stack, 'EventBridgeProxyApi');

httpApi.addRoutes({
path: '/put-events-on-my-event-bus',
methods: [ HttpMethod.PUT ],
integration: eventBridgeIntegration,
});
```


### Lambda

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ export interface HttpPrivateIntegrationOptions {
* @default HttpMethod.ANY
*/
readonly method?: HttpMethod;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import {
HttpRouteIntegrationBindOptions,
HttpRouteIntegrationConfig,
AwsServiceIntegrationSubtype,
} from '@aws-cdk/aws-apigatewayv2';
import { IEventBus } from '@aws-cdk/aws-events';
import { PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import { AwsServiceIntegration } from './private/integration';


export enum EventBridgeTargetAction {
PUT_EVENTS = 'EventBridge-PutEvents'
}

/**
* Properties to initialize `EventBridgeIntegration`.
*/
export interface EventBridgeIntegrationProps {
/**
* The EventBridge API action to integrate.
*/
readonly targetAction: EventBridgeTargetAction;

/**
* The target event bus.
*/
readonly eventBus: IEventBus;

/**
* The event source.
*/
readonly eventSource?: string;
Comment on lines +29 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this? Can you provide more details in the tsdoc?


/**
* The EventBridge PutEvents request parameters.
* @see https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEvents.html
*/
readonly requestParameters: EventBridgeIntegrationRequestParameters;
}
Comment on lines +34 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I go through this, something feels incorrect or odd here in terms of class modeling.

For one, the targetAction allows for other EventBridge APIs to be invoked but EventBridgeIntegrationRequestParameters is very specific to the PutEvents API.
It's not clear to me if this class should be EventBridgePutEventsIntegration. I'm aware this is conflicting with my previous comment - #13017 (comment). Perhaps we may have to go back to the previous model.

Second, the resources option allows customers to pass a set of ARNs. I would've assumed this would be the ARN of the APIGateway resource but it looks like this is configurable. When and why would this be done?
I suppose more generally - what is/are the use cases that customers are expected to use this integration?

Finally (probably least important here), we probably do not need an additional nested requestParameters section. Flattening it might suffice.


/**
* Integration request parameters for EventBridge
* @see https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEventsRequestEntry.html#eventbridge-Type-PutEventsRequestEntry-Detail
*/
export interface EventBridgeIntegrationRequestParameters {
/**
* A valid JSON string. There is no other schema imposed. The JSON string may contain fields and nested subobjects.
*
* @default none
*/
readonly detail?: string;

/**
* Free-form string used to decide what fields to expect in the event detail.
*
* @default none
*/
readonly detailType?: string;

/**
* The AWS region. NB: Particular to EventBridge-PutEvents API Gateway integration and not EventBridge's PutEvents API.
*
* @default none
*/
readonly region?: string;

/**
* AWS resources, identified by Amazon Resource Name (ARN), which the event primarily concerns. Any number,
* including zero, may be present.
*
* @default none
*/
readonly resources?: string[];

/**
* The source of the event.
*
* @default none
*/
readonly source?: string;

/**
* The time stamp of the event, per RFC3339. If no time stamp is provided, the time stamp of the PutEvents call is
* used.
*
* @default none
*/
readonly time?: string;
}

/**
* The EventBridge integration resource for HTTP API
*/
export class EventBridgeIntegration extends AwsServiceIntegration {
constructor(private readonly props: EventBridgeIntegrationProps) {
super();
}

public bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig {
switch (this.props.targetAction) {
case EventBridgeTargetAction.PUT_EVENTS:
this.integrationSubtype = AwsServiceIntegrationSubtype.EVENT_BRIDGE_PUT_EVENTS;
break;
default:
this.integrationSubtype = AwsServiceIntegrationSubtype.EVENT_BRIDGE_PUT_EVENTS;
}

const { scope } = options;

const role = new Role(scope, 'EventBridgeIntegrationRole', {
description: 'Role for API Gateway to publish Events',
assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),
});

role.addToPolicy(new PolicyStatement({
actions: ['events:PutEvents'],
resources: [this.props.eventBus.eventBusArn],
conditions: (() => !('eventSource' in this.props) ? undefined : {
StringEquals: {
'events:source': this.props.eventSource,
},
})(),
}));

return {
payloadFormatVersion: this.payloadFormatVersion,
type: this.integrationType,
connectionType: this.connectionType,
credentialsArn: role.roleArn,
integrationSubtype: this.integrationSubtype,
requestParameters: {
...this.props.requestParameters,
eventBusName: this.props.eventBus.eventBusName,
},
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ export class HttpProxyIntegration implements IHttpRouteIntegration {
uri: this.props.url,
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './nlb';
export * from './service-discovery';
export * from './http-proxy';
export * from './lambda';
export * from './eventbridge';
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ export class LambdaProxyIntegration implements IHttpRouteIntegration {
payloadFormatVersion: this.props.payloadFormatVersion ?? PayloadFormatVersion.VERSION_2_0,
};
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AwsServiceIntegrationSubtype,
HttpConnectionType,
HttpIntegrationType,
HttpRouteIntegrationBindOptions,
Expand All @@ -8,8 +9,8 @@ import {
HttpMethod,
IVpcLink,
} from '@aws-cdk/aws-apigatewayv2';
import * as ec2 from '@aws-cdk/aws-ec2';

import * as ec2 from '@aws-cdk/aws-ec2';

/**
* Options required to use an existing vpcLink or configure a new one
Expand Down Expand Up @@ -63,3 +64,17 @@ export abstract class HttpPrivateIntegration implements IHttpRouteIntegration {

public abstract bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig;
}

/**
* The HTTP Private integration resource for HTTP API
*
* @internal
*/
export abstract class AwsServiceIntegration implements IHttpRouteIntegration {
protected connectionType = HttpConnectionType.INTERNET
protected integrationSubtype?: AwsServiceIntegrationSubtype;
protected integrationType = HttpIntegrationType.AWS_PROXY;
protected payloadFormatVersion = PayloadFormatVersion.VERSION_1_0; // 1.0 is required and is the only supported format

public abstract bind(options: HttpRouteIntegrationBindOptions): HttpRouteIntegrationConfig;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
{
"Resources": {
"EventBus7B8748AA": {
"Type": "AWS::Events::EventBus",
"Properties": {
"Name": "integeventbridgeproxyEventBus554075B3"
}
},
"EventBridgeProxyApi73E23498": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "EventBridgeProxyApi",
"ProtocolType": "HTTP"
}
},
"EventBridgeProxyApiDefaultRouteEventBridgeIntegrationRole3A0AD809": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"Description": "Role for API Gateway to publish Events"
}
},
"EventBridgeProxyApiDefaultRouteEventBridgeIntegrationRoleDefaultPolicy3589E340": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "events:PutEvents",
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"EventBus7B8748AA",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "EventBridgeProxyApiDefaultRouteEventBridgeIntegrationRoleDefaultPolicy3589E340",
"Roles": [
{
"Ref": "EventBridgeProxyApiDefaultRouteEventBridgeIntegrationRole3A0AD809"
}
]
}
},
"EventBridgeProxyApiDefaultRoute7A237CAD": {
"Type": "AWS::ApiGatewayV2::Route",
"Properties": {
"ApiId": {
"Ref": "EventBridgeProxyApi73E23498"
},
"RouteKey": "$default",
"AuthorizationScopes": [],
"Target": {
"Fn::Join": [
"",
[
"integrations/",
{
"Ref": "EventBridgeProxyApiDefaultRouteHttpIntegrationb62e88a58be37f7ea08ce64ef6029d4a761DFA56"
}
]
]
}
}
},
"EventBridgeProxyApiDefaultRouteHttpIntegrationb62e88a58be37f7ea08ce64ef6029d4a761DFA56": {
"Type": "AWS::ApiGatewayV2::Integration",
"Properties": {
"ApiId": {
"Ref": "EventBridgeProxyApi73E23498"
},
"IntegrationType": "AWS_PROXY",
"ConnectionType": "INTERNET",
"CredentialsArn": {
"Fn::GetAtt": [
"EventBridgeProxyApiDefaultRouteEventBridgeIntegrationRole3A0AD809",
"Arn"
]
},
"IntegrationSubtype": "EventBridge-PutEvents",
"PayloadFormatVersion": "1.0",
"RequestParameters": {
"Detail": "$request.body.result",
"DetailType": "$request.body.description",
"EventBusName": {
"Ref": "EventBus7B8748AA"
},
"Source": "test",
"Time": "$context.requestTimeEpoch"
}
}
},
"EventBridgeProxyApiDefaultStage642846E1": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"ApiId": {
"Ref": "EventBridgeProxyApi73E23498"
},
"StageName": "$default",
"AutoDeploy": true
}
}
},
"Outputs": {
"Endpoint": {
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "EventBridgeProxyApi73E23498"
},
".execute-api.",
{
"Ref": "AWS::Region"
},
".",
{
"Ref": "AWS::URLSuffix"
},
"/"
]
]
}
}
}
}
Loading