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

refactor(apigateway): API cleanups #2903

Merged
merged 3 commits into from
Jun 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/authorizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Represents an API Gateway authorizer.
*/
export interface IAuthorizer {
/**
* The authorizer ID.
*/
readonly authorizerId: string;
}
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 @@ -11,6 +11,7 @@ export * from './usage-plan';
export * from './vpc-link';
export * from './methodresponse';
export * from './model';
export * from './authorizer';

// AWS::ApiGateway CloudFormation Resources:
export * from './apigateway.generated';
Expand Down
13 changes: 6 additions & 7 deletions packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Construct, Resource, Stack } from '@aws-cdk/cdk';
import { CfnMethod, CfnMethodProps } from './apigateway.generated';
import { IAuthorizer } from './authorizer';
import { ConnectionType, Integration } from './integration';
import { MockIntegration } from './integrations/mock';
import { MethodResponse } from './methodresponse';
Expand All @@ -23,11 +24,8 @@ export interface MethodOptions {
/**
* If `authorizationType` is `Custom`, this specifies the ID of the method
* authorizer resource.
*
* NOTE: in the future this will be replaced with an `IAuthorizer`
* construct.
*/
readonly authorizerId?: string;
readonly authorizer?: IAuthorizer;

/**
* Indicates whether the method requires clients to submit a valid API key.
Expand Down Expand Up @@ -108,6 +106,7 @@ export class Method extends Resource {
const options = props.options || {};

const defaultMethodOptions = props.resource.defaultMethodOptions || {};
const authorizer = options.authorizer || defaultMethodOptions.authorizer;

const methodProps: CfnMethodProps = {
resourceId: props.resource.resourceId,
Expand All @@ -116,7 +115,7 @@ export class Method extends Resource {
operationName: options.operationName || defaultMethodOptions.operationName,
apiKeyRequired: options.apiKeyRequired || defaultMethodOptions.apiKeyRequired,
authorizationType: options.authorizationType || defaultMethodOptions.authorizationType || AuthorizationType.None,
authorizerId: options.authorizerId || defaultMethodOptions.authorizerId,
authorizerId: authorizer && authorizer.authorizerId,
requestParameters: options.requestParameters,
integration: this.renderIntegration(props.integration),
methodResponses: this.renderMethodResponses(options.methodResponses),
Expand Down Expand Up @@ -153,15 +152,15 @@ export class Method extends Resource {
}

const stage = this.restApi.deploymentStage.stageName.toString();
return this.restApi.executeApiArn(this.httpMethod, this.resource.path, stage);
return this.restApi.arnForExecuteApi(this.httpMethod, this.resource.path, stage);
}

/**
* Returns an execute-api ARN for this method's "test-invoke-stage" stage.
* This stage is used by the AWS Console UI when testing the method.
*/
public get testMethodArn(): string {
return this.restApi.executeApiArn(this.httpMethod, this.resource.path, 'test-invoke-stage');
return this.restApi.arnForExecuteApi(this.httpMethod, this.resource.path, 'test-invoke-stage');
}

private renderIntegration(integration?: Integration): CfnMethod.IntegrationProperty {
Expand Down
37 changes: 20 additions & 17 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,30 +178,24 @@ export class RestApi extends Resource implements IRestApi {
public readonly restApiRootResourceId: string;

/**
* API Gateway deployment that represents the latest changes of the API.
* This resource will be automatically updated every time the REST API model changes.
* This will be undefined if `deploy` is false.
* Represents the root resource ("/") of this API. Use it to define the API model:
*
* api.root.addMethod('ANY', redirectToHomePage); // "ANY /"
* api.root.addResource('friends').addMethod('GET', getFriendsHandler); // "GET /friends"
*
*/
public latestDeployment?: Deployment;
public readonly root: IResource;

/**
* API Gateway stage that points to the latest deployment (if defined).
*
* If `deploy` is disabled, you will need to explicitly assign this value in order to
* set up integrations.
*/
public deploymentStage?: Stage;

/**
* Represents the root resource ("/") of this API. Use it to define the API model:
*
* api.root.addMethod('ANY', redirectToHomePage); // "ANY /"
* api.root.addResource('friends').addMethod('GET', getFriendsHandler); // "GET /friends"
*
*/
public readonly root: IResource;
public deploymentStage: Stage;

private readonly methods = new Array<Method>();
private _latestDeployment: Deployment | undefined;

constructor(scope: Construct, id: string, props: RestApiProps = { }) {
super(scope, id);
Expand Down Expand Up @@ -231,6 +225,15 @@ export class RestApi extends Resource implements IRestApi {
this.root = new RootResource(this, props, resource.attrRootResourceId);
}

/**
* API Gateway deployment that represents the latest changes of the API.
* This resource will be automatically updated every time the REST API model changes.
* This will be undefined if `deploy` is false.
eladb marked this conversation as resolved.
Show resolved Hide resolved
*/
public get latestDeployment() {
return this._latestDeployment;
}

/**
* The deployed root URL of this REST API.
*/
Expand Down Expand Up @@ -275,7 +278,7 @@ export class RestApi extends Resource implements IRestApi {
* @param path The resource path. Must start with '/' (default `*`)
* @param stage The stage (default `*`)
*/
public executeApiArn(method: string = '*', path: string = '/*', stage: string = '*') {
public arnForExecuteApi(method: string = '*', path: string = '/*', stage: string = '*') {
if (!path.startsWith('/')) {
throw new Error(`"path" must begin with a "/": '${path}'`);
}
Expand Down Expand Up @@ -317,7 +320,7 @@ export class RestApi extends Resource implements IRestApi {
const deploy = props.deploy === undefined ? true : props.deploy;
if (deploy) {

this.latestDeployment = new Deployment(this, 'Deployment', {
this._latestDeployment = new Deployment(this, 'Deployment', {
description: 'Automatically created by the RestApi construct',
api: this,
retainDeployments: props.retainDeployments
Expand All @@ -328,7 +331,7 @@ export class RestApi extends Resource implements IRestApi {
const stageName = (props.deployOptions && props.deployOptions.stageName) || 'prod';

this.deploymentStage = new Stage(this, `DeploymentStage.${stageName}`, {
deployment: this.latestDeployment,
deployment: this._latestDeployment,
...props.deployOptions
});

Expand Down
22 changes: 11 additions & 11 deletions packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ export interface ThrottlingPerMethod {
* The method for which you specify the throttling settings.
* @default none
*/
readonly method: Method,
readonly method: Method;

/**
* Specifies the overall request rate (average requests per second) and burst capacity.
* @default none
*/
readonly throttle: ThrottleSettings
readonly throttle: ThrottleSettings;
}

/**
Expand All @@ -90,57 +90,57 @@ export interface UsagePlanPerApiStage {
/**
* @default none
*/
readonly api?: IRestApi,
readonly api?: IRestApi;

/**
*
* [disable-awslint:ref-via-interface]
* @default none
*/
readonly stage?: Stage,
readonly stage?: Stage;

/**
* @default none
*/
readonly throttle?: ThrottlingPerMethod[]
readonly throttle?: ThrottlingPerMethod[];
}

export interface UsagePlanProps {
/**
* API Stages to be associated which the usage plan.
* @default none
*/
readonly apiStages?: UsagePlanPerApiStage[],
readonly apiStages?: UsagePlanPerApiStage[];

/**
* Represents usage plan purpose.
* @default none
*/
readonly description?: string,
readonly description?: string;

/**
* Number of requests clients can make in a given time period.
* @default none
*/
readonly quota?: QuotaSettings
readonly quota?: QuotaSettings;

/**
* Overall throttle settings for the API.
* @default none
*/
readonly throttle?: ThrottleSettings,
readonly throttle?: ThrottleSettings;

/**
* Name for this usage plan.
* @default none
*/
readonly name?: string
readonly name?: string;

/**
* ApiKey to be associated with the usage plan.
* @default none
*/
readonly apiKey?: IApiKey
readonly apiKey?: IApiKey;
}

export class UsagePlan extends Resource {
Expand Down
37 changes: 30 additions & 7 deletions packages/@aws-cdk/aws-apigateway/lib/vpc-link.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2');
import { Construct, Resource } from '@aws-cdk/cdk';
import { Construct, Lazy, Resource } from '@aws-cdk/cdk';
import { CfnVpcLink } from './apigateway.generated';

/**
Expand All @@ -8,9 +8,9 @@ import { CfnVpcLink } from './apigateway.generated';
export interface VpcLinkProps {
/**
* The name used to label and identify the VPC link.
* @default automatically generated name
* @default - automatically generated name
*/
readonly name?: string;
readonly vpcLinkName?: string;

/**
* The description of the VPC link.
Expand All @@ -21,8 +21,10 @@ export interface VpcLinkProps {
/**
* The network load balancers of the VPC targeted by the VPC link.
* The network load balancers must be owned by the same AWS account of the API owner.
*
* @default - no targets. Use `addTargets` to add targets
*/
readonly targets: elbv2.INetworkLoadBalancer[];
readonly targets?: elbv2.INetworkLoadBalancer[];
}

/**
Expand All @@ -36,15 +38,36 @@ export class VpcLink extends Resource {
*/
public readonly vpcLinkId: string;

constructor(scope: Construct, id: string, props: VpcLinkProps) {
private readonly targets = new Array<elbv2.INetworkLoadBalancer>();

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

const cfnResource = new CfnVpcLink(this, 'Resource', {
name: props.name || this.node.uniqueId,
name: props.vpcLinkName || this.node.uniqueId,
description: props.description,
targetArns: props.targets.map(nlb => nlb.loadBalancerArn)
targetArns: Lazy.listValue({ produce: () => this.renderTargets() })
});

this.vpcLinkId = cfnResource.refAsString;

if (props.targets) {
this.addTargets(...props.targets);
}
}

public addTargets(...targets: elbv2.INetworkLoadBalancer[]) {
this.targets.push(...targets);
}

protected validate(): string[] {
if (this.targets.length === 0) {
return [ `No targets added to vpc link` ];
}
return [];
}

private renderTargets() {
return this.targets.map(nlb => nlb.loadBalancerArn);
}
}
8 changes: 4 additions & 4 deletions packages/@aws-cdk/aws-apigateway/test/test.restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ export = {
api.root.addMethod('GET');

// WHEN
const arn = api.executeApiArn('method', '/path', 'stage');
const arn = api.arnForExecuteApi('method', '/path', 'stage');

// THEN
test.deepEqual(stack.resolve(arn), { 'Fn::Join':
Expand All @@ -426,7 +426,7 @@ export = {
api.root.addMethod('GET');

// THEN
test.throws(() => api.executeApiArn('method', 'hey-path', 'stage'), /"path" must begin with a "\/": 'hey-path'/);
test.throws(() => api.arnForExecuteApi('method', 'hey-path', 'stage'), /"path" must begin with a "\/": 'hey-path'/);
test.done();
},

Expand Down Expand Up @@ -534,7 +534,7 @@ export = {
const api = new apigateway.RestApi(stack, 'myapi', {
defaultIntegration: rootInteg,
defaultMethodOptions: {
authorizerId: 'AUTHID',
authorizer: { authorizerId: 'AUTHID' },
authorizationType: apigateway.AuthorizationType.IAM,
}
});
Expand All @@ -553,7 +553,7 @@ export = {
const child2 = api.root.addResource('child2', {
defaultIntegration: new apigateway.MockIntegration(),
defaultMethodOptions: {
authorizerId: 'AUTHID2',
authorizer: { authorizerId: 'AUTHID2' },
}
});

Expand Down
Loading