Skip to content

Commit

Permalink
feat(apigatewayv2): set throttling on stages (#19776)
Browse files Browse the repository at this point in the history
fixes #19626

added integ tests
let me know if change to readme is necessary

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [x] Did you use `cdk-integ` to deploy the infrastructure and generate the snapshot (i.e. `cdk-integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
peterwoodworth authored and otaviomacedo committed Apr 11, 2022
1 parent 87ca3ab commit 9e05478
Show file tree
Hide file tree
Showing 17 changed files with 466 additions and 1 deletion.
24 changes: 24 additions & 0 deletions packages/@aws-cdk/aws-apigatewayv2/lib/common/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ export interface StageOptions {
* @default - no custom domain and api mapping configuration
*/
readonly domainMapping?: DomainMappingOptions;

/**
* Throttle settings for the routes of this stage
*
* @default - no throttling configuration
*/
readonly throttle?: ThrottleSettings;
}

/**
Expand All @@ -70,3 +77,20 @@ export interface StageAttributes {
*/
readonly stageName: string;
}

/**
* Container for defining throttling parameters to API stages
*/
export interface ThrottleSettings {
/**
* The API request steady-state rate limit (average requests per second over an extended period of time)
* @default none
*/
readonly rateLimit?: number;

/**
* The maximum API request rate limit over a time ranging from one to a few seconds.
* @default none
*/
readonly burstLimit?: number;
}
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-apigatewayv2/lib/http/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ export class HttpStage extends HttpStageBase {
apiId: props.httpApi.apiId,
stageName: this.physicalName,
autoDeploy: props.autoDeploy,
defaultRouteSettings: !props.throttle ? undefined : {
throttlingBurstLimit: props.throttle?.burstLimit,
throttlingRateLimit: props.throttle?.rateLimit,
},
});

this.stageName = this.physicalName;
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-apigatewayv2/lib/websocket/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ export class WebSocketStage extends StageBase implements IWebSocketStage {
apiId: props.webSocketApi.apiId,
stageName: this.physicalName,
autoDeploy: props.autoDeploy,
defaultRouteSettings: !props.throttle ? undefined : {
throttlingBurstLimit: props.throttle?.burstLimit,
throttlingRateLimit: props.throttle?.rateLimit,
},
});

if (props.domainMapping) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"Resources": {
"HttpApiF5A9A8A7": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "HttpApi",
"ProtocolType": "HTTP"
}
},
"HttpStageWithPropertiesC0AABA83": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"ApiId": {
"Ref": "HttpApiF5A9A8A7"
},
"StageName": "$default",
"DefaultRouteSettings": {
"ThrottlingBurstLimit": 1000,
"ThrottlingRateLimit": 1000
}
}
}
}
}
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-apigatewayv2/test/http/integ.stage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import * as apigw from '../../lib';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-cdk-aws-apigatewayv2-http-stage');

const httpApi = new apigw.HttpApi(stack, 'HttpApi', { createDefaultStage: false });
new apigw.HttpStage(stack, 'HttpStageWithProperties', {
httpApi,
throttle: {
rateLimit: 1000,
burstLimit: 1000,
},
});

app.synth();
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"Resources": {
"HttpApiF5A9A8A7": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "HttpApi",
"ProtocolType": "HTTP"
}
},
"HttpStageWithPropertiesC0AABA83": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"ApiId": {
"Ref": "HttpApiF5A9A8A7"
},
"StageName": "$default",
"DefaultRouteSettings": {
"ThrottlingBurstLimit": 1000,
"ThrottlingRateLimit": 1000
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"17.0.0"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "17.0.0",
"artifacts": {
"Tree": {
"type": "cdk:tree",
"properties": {
"file": "tree.json"
},
"metadata": {}
},
"aws-cdk-aws-apigatewayv2-http-stage": {
"type": "aws:cloudformation:stack",
"environment": "aws://unknown-account/unknown-region",
"properties": {
"templateFile": "aws-cdk-aws-apigatewayv2-http-stage.template.json",
"validateOnSynth": false
},
"metadata": {
"/aws-cdk-aws-apigatewayv2-http-stage/HttpApi/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "HttpApiF5A9A8A7"
}
],
"/aws-cdk-aws-apigatewayv2-http-stage/HttpStageWithProperties/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "HttpStageWithPropertiesC0AABA83"
}
]
},
"displayName": "aws-cdk-aws-apigatewayv2-http-stage"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"version": "tree-0.1",
"tree": {
"id": "App",
"path": "",
"children": {
"Tree": {
"id": "Tree",
"path": "Tree",
"constructInfo": {
"fqn": "@aws-cdk/core.Construct",
"version": "0.0.0"
}
},
"aws-cdk-aws-apigatewayv2-http-stage": {
"id": "aws-cdk-aws-apigatewayv2-http-stage",
"path": "aws-cdk-aws-apigatewayv2-http-stage",
"children": {
"HttpApi": {
"id": "HttpApi",
"path": "aws-cdk-aws-apigatewayv2-http-stage/HttpApi",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-aws-apigatewayv2-http-stage/HttpApi/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Api",
"aws:cdk:cloudformation:props": {
"name": "HttpApi",
"protocolType": "HTTP"
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-apigatewayv2.CfnApi",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-apigatewayv2.HttpApi",
"version": "0.0.0"
}
},
"HttpStageWithProperties": {
"id": "HttpStageWithProperties",
"path": "aws-cdk-aws-apigatewayv2-http-stage/HttpStageWithProperties",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-aws-apigatewayv2-http-stage/HttpStageWithProperties/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Stage",
"aws:cdk:cloudformation:props": {
"apiId": {
"Ref": "HttpApiF5A9A8A7"
},
"stageName": "$default",
"defaultRouteSettings": {
"throttlingBurstLimit": 1000,
"throttlingRateLimit": 1000
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-apigatewayv2.CfnStage",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-apigatewayv2.HttpStage",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/core.Stack",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/core.App",
"version": "0.0.0"
}
}
}
29 changes: 28 additions & 1 deletion packages/@aws-cdk/aws-apigatewayv2/test/http/stage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,31 @@ describe('HttpStage with domain mapping', () => {

expect(t).toThrow(/domainUrl is not available when no API mapping is associated with the Stage/);
});
});

test('correctly sets throttle settings', () => {
// GIVEN
const stack = new Stack();
const api = new HttpApi(stack, 'Api', {
createDefaultStage: false,
});

// WHEN
new HttpStage(stack, 'DefaultStage', {
httpApi: api,
throttle: {
burstLimit: 1000,
rateLimit: 1000,
},
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Stage', {
ApiId: stack.resolve(api.apiId),
StageName: '$default',
DefaultRouteSettings: {
ThrottlingBurstLimit: 1000,
ThrottlingRateLimit: 1000,
},
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"Resources": {
"WebSocketApi34BCF99B": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "WebSocketApi",
"ProtocolType": "WEBSOCKET",
"RouteSelectionExpression": "$request.body.action"
}
},
"WebSocketStageC46B7E43": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"ApiId": {
"Ref": "WebSocketApi34BCF99B"
},
"StageName": "dev",
"DefaultRouteSettings": {
"ThrottlingBurstLimit": 1000,
"ThrottlingRateLimit": 1000
}
}
}
}
}
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-apigatewayv2/test/websocket/integ.stage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import * as apigw from '../../lib';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-cdk-aws-apigatewayv2-websocket-stage');

const webSocketApi = new apigw.WebSocketApi(stack, 'WebSocketApi');
new apigw.WebSocketStage(stack, 'WebSocketStage', {
webSocketApi,
stageName: 'dev',
throttle: {
rateLimit: 1000,
burstLimit: 1000,
},
});

app.synth();
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"Resources": {
"WebSocketApi34BCF99B": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "WebSocketApi",
"ProtocolType": "WEBSOCKET",
"RouteSelectionExpression": "$request.body.action"
}
},
"WebSocketStageC46B7E43": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"ApiId": {
"Ref": "WebSocketApi34BCF99B"
},
"StageName": "dev",
"DefaultRouteSettings": {
"ThrottlingBurstLimit": 1000,
"ThrottlingRateLimit": 1000
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"17.0.0"}
Loading

0 comments on commit 9e05478

Please sign in to comment.