Skip to content

Commit

Permalink
feat(apigateway): support for UsagePlan, ApiKey, UsagePlanKey (#2564)
Browse files Browse the repository at this point in the history
Add support for UsagePlan, ApiKey, UsagePlanKey.

Fixes #723.
  • Loading branch information
orangewise authored and rix0rrr committed May 28, 2019
1 parent 1a7d4db commit 203f114
Show file tree
Hide file tree
Showing 12 changed files with 704 additions and 5 deletions.
3 changes: 2 additions & 1 deletion install.sh
Expand Up @@ -16,5 +16,6 @@ npm ci --global-style
export PATH=node_modules/.bin:$PATH

echo "============================================================================================="
echo "bootstrapping..."
echo "cleanup and start bootstrapping..."
lerna clean --yes
lerna bootstrap --reject-cycles --ci
36 changes: 36 additions & 0 deletions packages/@aws-cdk/aws-apigateway/README.md
Expand Up @@ -104,6 +104,42 @@ book.addMethod('GET', getBookIntegration, {
});
```

The following example shows how to use an API Key with a usage plan:

```ts
const hello = new lambda.Function(this, 'hello', {
runtime: lambda.Runtime.NodeJS810,
handler: 'hello.handler',
code: lambda.Code.asset('lambda')
});

const api = new apigateway.RestApi(this, 'hello-api', { });
const integration = new apigateway.LambdaIntegration(hello);

const v1 = api.root.addResource('v1');
const echo = v1.addResource('echo');
const echoMethod = echo.addMethod('GET', integration, { apiKeyRequired: true });
const key = api.addApiKey('ApiKey');

const plan = api.addUsagePlan('UsagePlan', {
name: 'Easy',
apiKey: key
});

plan.addApiStage({
stage: api.deploymentStage,
throttle: [
{
method: echoMethod,
throttle: {
rateLimit: 10,
burstLimit: 2
}
}
]
});
```

#### Default Integration and Method Options

The `defaultIntegration` and `defaultMethodOptions` properties can be used to
Expand Down
112 changes: 112 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/api-key.ts
@@ -0,0 +1,112 @@
import { Construct, IResource as IResourceBase, Resource } from '@aws-cdk/cdk';
import { CfnApiKey } from './apigateway.generated';
import { ResourceOptions } from "./resource";
import { RestApi } from './restapi';

/**
* API keys are alphanumeric string values that you distribute to
* app developer customers to grant access to your API
*/
export interface ApiKeyAttributes {
/**
* The API key ID.
* @attribute
*/
readonly keyId: string;
}

/**
* API keys are alphanumeric string values that you distribute to
* app developer customers to grant access to your API
*/
export interface IApiKey extends IResourceBase {
/**
* The API key ID.
* @attribute
*/
readonly keyId: string;
}

/**
* ApiKey Properties.
*/
export interface ApiKeyProps extends ResourceOptions {
/**
* A list of resources this api key is associated with.
* @default none
*/
readonly resources?: RestApi[];

/**
* An AWS Marketplace customer identifier to use when integrating with the AWS SaaS Marketplace.
* @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-customerid
* @default none
*/
readonly customerId?: string;

/**
* A description of the purpose of the API key.
* @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-description
* @default none
*/
readonly description?: string;

/**
* Indicates whether the API key can be used by clients.
* @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-enabled
* @default true
*/
readonly enabled?: boolean;

/**
* Specifies whether the key identifier is distinct from the created API key value.
* @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-generatedistinctid
* @default false
*/
readonly generateDistinctId?: boolean;

/**
* A name for the API key. If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the API key name.
* @link http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-apikey.html#cfn-apigateway-apikey-name
* @default automically generated name
*/
readonly name?: string;
}

/**
* An API Gateway ApiKey.
*
* An ApiKey can be distributed to API clients that are executing requests
* for Method resources that require an Api Key.
*/
export class ApiKey extends Resource implements IApiKey {
public readonly keyId: string;

constructor(scope: Construct, id: string, props: ApiKeyProps = { }) {
super(scope, id);

const resource = new CfnApiKey(this, 'Resource', {
customerId: props.customerId,
description: props.description,
enabled: props.enabled || true,
generateDistinctId: props.generateDistinctId,
name: props.name,
stageKeys: this.renderStageKeys(props.resources)
});

this.keyId = resource.ref;
}

private renderStageKeys(resources: RestApi[] | undefined): CfnApiKey.StageKeyProperty[] | undefined {
if (!resources) {
return undefined;
}

return resources.map((resource: RestApi) => {
const restApi = resource;
const restApiId = restApi.restApiId;
const stageName = restApi.deploymentStage!.stageName.toString();
return { restApiId, stageName };
});
}
}
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/index.ts
Expand Up @@ -6,6 +6,8 @@ export * from './deployment';
export * from './stage';
export * from './integrations';
export * from './lambda-api';
export * from './api-key';
export * from './usage-plan';
export * from './vpc-link';
export * from './methodresponse';
export * from './model';
Expand Down
18 changes: 18 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
@@ -1,11 +1,13 @@
import iam = require('@aws-cdk/aws-iam');
import { CfnOutput, Construct, IResource as IResourceBase, Resource } from '@aws-cdk/cdk';
import { ApiKey, IApiKey } from './api-key';
import { CfnAccount, CfnRestApi } from './apigateway.generated';
import { Deployment } from './deployment';
import { Integration } from './integration';
import { Method, MethodOptions } from './method';
import { IResource, ResourceBase, ResourceOptions } from './resource';
import { Stage, StageOptions } from './stage';
import { UsagePlan, UsagePlanProps } from './usage-plan';

export interface IRestApi extends IResourceBase {
/**
Expand Down Expand Up @@ -249,6 +251,22 @@ export class RestApi extends Resource implements IRestApi {
return this.deploymentStage.urlForPath(path);
}

/**
* Adds a usage plan.
*/
public addUsagePlan(id: string, props: UsagePlanProps): UsagePlan {
return new UsagePlan(this, id, props);
}

/**
* Add an ApiKey
*/
public addApiKey(id: string): IApiKey {
return new ApiKey(this, id, {
resources: [this]
});
}

/**
* @returns The "execute-api" ARN.
* @default "*" returns the execute API ARN for all methods/resources in
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/stage.ts
Expand Up @@ -163,7 +163,7 @@ export class Stage extends Resource {
*/
public readonly stageName: string;

private readonly restApi: IRestApi;
public readonly restApi: IRestApi;
private enableCacheCluster?: boolean;

constructor(scope: Construct, id: string, props: StageProps) {
Expand Down

0 comments on commit 203f114

Please sign in to comment.