forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aws-apigateway): add support for UsagePlan, ApiKey, UsagePlanKey (…
- Loading branch information
Akkaash Goel
committed
Nov 20, 2018
1 parent
d3b8448
commit a0aee19
Showing
10 changed files
with
586 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import cdk = require('@aws-cdk/cdk'); | ||
import { cloudformation } from './apigateway.generated'; | ||
import { IRestApiResource } from "./resource"; | ||
import { RestApi } from './restapi'; | ||
|
||
export interface ApiKeyProps { | ||
/** | ||
* A list of resources this api key is associated with. | ||
*/ | ||
resources?: IRestApiResource[]; | ||
/** | ||
* AWS Marketplace customer identifier to distribute this key to. | ||
*/ | ||
customerId?: string; | ||
/** | ||
* Purpose of the API Key | ||
*/ | ||
description?: string; | ||
/** | ||
* Whether this API Key is enabled for use. | ||
*/ | ||
enabled?: boolean; | ||
/** | ||
* Distinguish the key identifier from the key value | ||
*/ | ||
generateDistinctId?: boolean; | ||
/** | ||
* Name of the key | ||
*/ | ||
name?: string; | ||
} | ||
|
||
/** | ||
* Creates 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 cdk.Construct { | ||
public readonly keyId: string; | ||
constructor(parent: cdk.Construct, id: string, props?: ApiKeyProps) { | ||
super(parent, id); | ||
|
||
const customerId = props ? props!.customerId : undefined; | ||
const description = props ? props!.description : undefined; | ||
const enabled = props ? props!.enabled : undefined; | ||
const generateDistinctId = props ? props!.generateDistinctId : undefined; | ||
const name = props ? props!.name : undefined; | ||
const stageKeys = this.renderStageKeys(props ? props!.resources : undefined); | ||
|
||
const apiKeyResourceProps: cloudformation.ApiKeyResourceProps = { | ||
customerId, | ||
description, | ||
enabled, | ||
generateDistinctId, | ||
name, | ||
stageKeys | ||
}; | ||
|
||
const resource: cloudformation.ApiKeyResource = new cloudformation.ApiKeyResource(this, 'Resource', apiKeyResourceProps); | ||
|
||
this.keyId = resource.ref; | ||
} | ||
|
||
private renderStageKeys(resources: IRestApiResource[] | undefined): cloudformation.ApiKeyResource.StageKeyProperty[] | undefined { | ||
if (!resources) { | ||
return undefined; | ||
} | ||
|
||
const stageKeys = new Array<cloudformation.ApiKeyResource.StageKeyProperty>(); | ||
resources.forEach((resource: IRestApiResource) => { | ||
const restApi: RestApi = resource.resourceApi; | ||
const restApiId = restApi.restApiId; | ||
const stageName = restApi!.deploymentStage!.stageName.toString(); | ||
stageKeys.push({ | ||
restApiId, | ||
stageName | ||
}); | ||
}); | ||
|
||
return stageKeys; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import cdk = require('@aws-cdk/cdk'); | ||
import { ApiKey } from './api-key'; | ||
import { cloudformation } from './apigateway.generated'; | ||
import { UsagePlan } from './usage-plan'; | ||
|
||
export interface UsagePlanKeyProps { | ||
/** | ||
* Represents the clients to apply a Usage Plan | ||
*/ | ||
apiKey: ApiKey, | ||
/** | ||
* Usage Plan to be associated. | ||
*/ | ||
usagePlan: UsagePlan | ||
} | ||
|
||
/** | ||
* Type of Usage Plan Key. Currently the only supported type is 'API_KEY' | ||
*/ | ||
export enum UsagePlanKeyType { | ||
ApiKey = 'API_KEY' | ||
} | ||
|
||
/** | ||
* Associates client with an API Gateway Usage Plan. | ||
*/ | ||
export class UsagePlanKey extends cdk.Construct { | ||
constructor(parent: cdk.Construct, name: string, props: UsagePlanKeyProps) { | ||
super(parent, name); | ||
|
||
new cloudformation.UsagePlanKeyResource(this, 'Resource', { | ||
keyId: props.apiKey.keyId, | ||
keyType: UsagePlanKeyType.ApiKey, | ||
usagePlanId: props.usagePlan.usagePlanId | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import cdk = require('@aws-cdk/cdk'); | ||
import { cloudformation } from './apigateway.generated'; | ||
import { Method } from './method'; | ||
import { IRestApiResource } from './resource'; | ||
import { Stage } from './stage'; | ||
|
||
/** | ||
* Container for defining throttling parameters to API stages or methods. | ||
* See link for more API Gateway's Request Throttling. | ||
* | ||
* @link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html | ||
*/ | ||
export interface ThrottleSettings { | ||
/** | ||
* Represents the steady-state rate for the API stage or method. | ||
*/ | ||
rateLimit?: number | ||
/** | ||
* Represents the burst size (i.e. maximum bucket size) for the API stage or method. | ||
*/ | ||
burstLimit?: number, | ||
} | ||
|
||
/** | ||
* Time period for which quota settings apply. | ||
*/ | ||
export enum Period { | ||
Day = 'DAY', | ||
Week = 'WEEK', | ||
Month = 'MONTH' | ||
} | ||
|
||
/** | ||
* Specifies the maximum number of requests that clients can make to API Gateway APIs. | ||
*/ | ||
export interface QuotaSettings { | ||
/** | ||
* Maximum number of requests that can be made in a given time period. | ||
*/ | ||
limit?: number, | ||
/** | ||
* Number of requests to reduce from the limit for the first time period. | ||
*/ | ||
offset?: number, | ||
/** | ||
* Time period to which the maximum limit applies. Valid values are DAY, WEEK or MONTH. | ||
*/ | ||
period?: Period | ||
} | ||
|
||
/** | ||
* Represents per-method throttling for a resource. | ||
*/ | ||
export interface ThrottlingPerMethod { | ||
method: Method, | ||
throttle: ThrottleSettings | ||
} | ||
|
||
/** | ||
* Represents the API stages that a usage plan applies to. | ||
*/ | ||
export interface UsagePlanPerApiStage { | ||
api?: IRestApiResource, | ||
stage?: Stage, | ||
throttle?: ThrottlingPerMethod[] | ||
} | ||
|
||
export interface UsagePlanProps { | ||
/** | ||
* API Stages to be associated which the usage plan. | ||
*/ | ||
apiStages?: UsagePlanPerApiStage[], | ||
/** | ||
* Represents usage plan purpose. | ||
*/ | ||
description?: string, | ||
/** | ||
* Number of requests clients can make in a given time period. | ||
*/ | ||
quota?: QuotaSettings | ||
/** | ||
* Overall throttle settings for the API. | ||
*/ | ||
throttle?: ThrottleSettings, | ||
/** | ||
* Name for this usage plan. | ||
*/ | ||
name?: string, | ||
} | ||
|
||
export class UsagePlan extends cdk.Construct { | ||
public readonly usagePlanId: string; | ||
constructor(parent: cdk.Construct, name: string, props?: UsagePlanProps) { | ||
super(parent, name); | ||
let resource: cloudformation.UsagePlanResource; | ||
if (props !== undefined) { | ||
const overallThrottle: cloudformation.UsagePlanResource.ThrottleSettingsProperty = this.renderThrottle(props.throttle); | ||
const quota: cloudformation.UsagePlanResource.QuotaSettingsProperty | undefined = this.renderQuota(props); | ||
const apiStages: cloudformation.UsagePlanResource.ApiStageProperty[] | undefined = this.renderApiStages(props); | ||
|
||
resource = new cloudformation.UsagePlanResource(this, 'Resource', { | ||
apiStages, | ||
description: props.description, | ||
quota, | ||
throttle: overallThrottle, | ||
usagePlanName: props.name, | ||
}); | ||
} else { | ||
resource = new cloudformation.UsagePlanResource(this, 'Resource'); | ||
} | ||
|
||
this.usagePlanId = resource.ref; | ||
} | ||
|
||
private renderApiStages(props: UsagePlanProps): cloudformation.UsagePlanResource.ApiStageProperty[] | undefined { | ||
if (props.apiStages && props.apiStages.length > 0) { | ||
const apiStages: cloudformation.UsagePlanResource.ApiStageProperty[] = []; | ||
props.apiStages.forEach((value: UsagePlanPerApiStage) => { | ||
const apiId = value.api ? value.api.resourceApi.restApiId : undefined; | ||
const stage = value.stage ? value.stage.stageName.toString() : undefined; | ||
const throttle = this.renderThrottlePerMethod(value.throttle); | ||
apiStages.push({ | ||
apiId, | ||
stage, | ||
throttle | ||
}); | ||
}); | ||
return apiStages; | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
private renderThrottlePerMethod(throttlePerMethod?: ThrottlingPerMethod[]): { | ||
[key: string]: (cloudformation.UsagePlanResource.ThrottleSettingsProperty | cdk.Token) | ||
} { | ||
const ret: { [key: string]: (cloudformation.UsagePlanResource.ThrottleSettingsProperty | cdk.Token) } = {}; | ||
|
||
if (throttlePerMethod && throttlePerMethod.length > 0) { | ||
throttlePerMethod.forEach((value: ThrottlingPerMethod) => { | ||
const method: Method = value.method; | ||
// this methodId is resource path and method for example /GET or /pets/GET | ||
const methodId = `${method.resource.resourcePath}/${method.httpMethod}`; | ||
ret[methodId] = this.renderThrottle(value.throttle); | ||
}); | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
private renderQuota(props: UsagePlanProps): cloudformation.UsagePlanResource.QuotaSettingsProperty | undefined { | ||
if (props.quota === undefined) { | ||
return undefined; | ||
} | ||
return { | ||
limit: props.quota ? props.quota.limit : undefined, | ||
offset: props.quota ? props.quota.offset : undefined, | ||
period: props.quota ? props.quota.period : undefined | ||
}; | ||
} | ||
|
||
private renderThrottle(throttleSettings?: ThrottleSettings): cloudformation.UsagePlanResource.ThrottleSettingsProperty { | ||
const throttle: cloudformation.UsagePlanResource.ThrottleSettingsProperty = {}; | ||
if (throttleSettings !== undefined) { | ||
const burstLimit: number|undefined = throttleSettings.burstLimit; | ||
if (burstLimit) { | ||
if (!Number.isInteger(burstLimit)) { | ||
throw new Error('Throttle burst limit should be an integer'); | ||
} | ||
throttle.burstLimit = Number.isInteger(burstLimit) ? burstLimit : undefined; | ||
} | ||
throttle.rateLimit = throttleSettings.rateLimit; | ||
} | ||
return throttle; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.