Skip to content

Commit

Permalink
feat(apigateway): gateway responses (#7441)
Browse files Browse the repository at this point in the history
closes #7071
  • Loading branch information
nirvana124 committed Apr 27, 2020
1 parent 9aff357 commit b0a65c1
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 1 deletion.
27 changes: 27 additions & 0 deletions packages/@aws-cdk/aws-apigateway/README.md
Expand Up @@ -33,6 +33,7 @@ running on AWS Lambda, or any web application.
- [Access Logging](#access-logging)
- [Cross Origin Resource Sharing (CORS)](cross-origin-resource-sharing-cors)
- [Endpoint Configuration](#endpoint-configuration)
- [Gateway Response](#gateway-response)
- [APIGateway v2](#apigateway-v2)

## Defining APIs
Expand Down Expand Up @@ -867,6 +868,32 @@ By performing this association, we can invoke the API gateway using the followin
https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}
```
## Gateway response
If the Rest API fails to process an incoming request, it returns to the client an error response without forwarding the
request to the integration backend. API Gateway has a set of standard response messages that are sent to the client for
each type of error. These error responses can be configured on the Rest API. The list of Gateway responses that can be
configured can be found [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html).
Learn more about [Gateway
Responses](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html).
The following code configures a Gateway Response when the response is 'access denied':
```ts
const api = new apigateway.RestApi(this, 'books-api');
api.addGatewayResponse('test-response', {
type: ResponseType.ACCESS_DENIED,
statusCode: '500',
responseHeaders: {
'Access-Control-Allow-Origin': "test.com",
'test-key': 'test-value'
},
templates: {
'application/json': '{ "message": $context.error.messageString, "statusCode": "488", "type": "$context.error.responseType" }'
}
});
```
## APIGateway v2
APIGateway v2 APIs are now moved to its own package named `aws-apigatewayv2`. For backwards compatibility, existing
Expand Down
210 changes: 210 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/gateway-response.ts
@@ -0,0 +1,210 @@
import { Construct, IResource, Resource } from '@aws-cdk/core';
import { CfnGatewayResponse } from './apigateway.generated';
import { IRestApi } from './restapi';

/**
* Represents gateway response resource.
*/
export interface IGatewayResponse extends IResource {
}

/**
* Properties for a new gateway response.
*/
export interface GatewayResponseProps extends GatewayResponseOptions {
/**
* Rest api resource to target.
*/
readonly restApi: IRestApi;
}

/**
* Options to add gateway response.
*/
export interface GatewayResponseOptions {
/**
* Response type to associate with gateway response.
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html
*/
readonly type: ResponseType;

/**
* Http status code for response.
* @default - standard http status code for the response type.
*/
readonly statusCode?: string;

/**
* Custom headers parameters for response.
* @default - no headers
*/
readonly responseHeaders?: { [key: string]: string };

/**
* Custom templates to get mapped as response.
* @default - Response from api will be returned without applying any transformation.
*/
readonly templates?: { [key: string]: string };

}

/**
* Configure the response received by clients, produced from the API Gateway backend.
*
* @resource AWS::ApiGateway::GatewayResponse
*/
export class GatewayResponse extends Resource implements IGatewayResponse {
constructor(scope: Construct, id: string, props: GatewayResponseProps) {
super(scope, id);

const resource = new CfnGatewayResponse(this, 'Resource', {
restApiId: props.restApi.restApiId,
responseType: props.type.responseType,
responseParameters: this.buildResponseParameters(props.responseHeaders),
responseTemplates: props.templates,
statusCode: props.statusCode,
});

this.node.defaultChild = resource;
}

private buildResponseParameters(responseHeaders?: { [key: string]: string }): { [key: string]: string } | undefined {
if (!responseHeaders) {
return undefined;
}

const responseParameters: { [key: string]: string } = {};
for (const [header, value] of Object.entries(responseHeaders)) {
responseParameters[`gatewayresponse.header.${header}`] = value;
}
return responseParameters;
}
}

/**
* Supported types of gateway responses.
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html
*/
export class ResponseType {
/**
* The gateway response for authorization failure.
*/
public static readonly ACCESS_DENIED = new ResponseType('ACCESS_DENIED');

/**
* The gateway response for an invalid API configuration.
*/
public static readonly API_CONFIGURATION_ERROR = new ResponseType('API_CONFIGURATION_ERROR');

/**
* The gateway response when a custom or Amazon Cognito authorizer failed to authenticate the caller.
*/
public static readonly AUTHORIZER_FAILURE = new ResponseType('AUTHORIZER_FAILURE');

/**
* The gateway response for failing to connect to a custom or Amazon Cognito authorizer.
*/
public static readonly AUTHORIZER_CONFIGURATION_ERROR = new ResponseType('AUTHORIZER_CONFIGURATION_ERROR');

/**
* The gateway response when the request parameter cannot be validated according to an enabled request validator.
*/
public static readonly BAD_REQUEST_PARAMETERS = new ResponseType('BAD_REQUEST_PARAMETERS');

/**
* The gateway response when the request body cannot be validated according to an enabled request validator.
*/
public static readonly BAD_REQUEST_BODY = new ResponseType('BAD_REQUEST_BODY');

/**
* The default gateway response for an unspecified response type with the status code of 4XX.
*/
public static readonly DEFAULT_4XX = new ResponseType('DEFAULT_4XX');

/**
* The default gateway response for an unspecified response type with a status code of 5XX.
*/
public static readonly DEFAULT_5XX = new ResponseType('DEFAULT_5XX');

/**
* The gateway response for an AWS authentication token expired error.
*/
public static readonly EXPIRED_TOKEN = new ResponseType('EXPIRED_TOKEN');

/**
* The gateway response for an invalid AWS signature error.
*/
public static readonly INVALID_SIGNATURE = new ResponseType('INVALID_SIGNATURE');

/**
* The gateway response for an integration failed error.
*/
public static readonly INTEGRATION_FAILURE = new ResponseType('INTEGRATION_FAILURE');

/**
* The gateway response for an integration timed out error.
*/
public static readonly INTEGRATION_TIMEOUT = new ResponseType('INTEGRATION_TIMEOUT');

/**
* The gateway response for an invalid API key submitted for a method requiring an API key.
*/
public static readonly INVALID_API_KEY = new ResponseType('INVALID_API_KEY');

/**
* The gateway response for a missing authentication token error,
* including the cases when the client attempts to invoke an unsupported API method or resource.
*/
public static readonly MISSING_AUTHENTICATION_TOKEN = new ResponseType('MISSING_AUTHENTICATION_TOKEN');

/**
* The gateway response for the usage plan quota exceeded error.
*/
public static readonly QUOTA_EXCEEDED = new ResponseType('QUOTA_EXCEEDED');

/**
* The gateway response for the request too large error.
*/
public static readonly REQUEST_TOO_LARGE = new ResponseType('REQUEST_TOO_LARGE');

/**
* The gateway response when API Gateway cannot find the specified resource
* after an API request passes authentication and authorization.
*/
public static readonly RESOURCE_NOT_FOUND = new ResponseType('RESOURCE_NOT_FOUND');

/**
* The gateway response when usage plan, method, stage, or account level throttling limits exceeded.
*/
public static readonly THROTTLED = new ResponseType('THROTTLED');

/**
* The gateway response when the custom or Amazon Cognito authorizer failed to authenticate the caller.
*/
public static readonly UNAUTHORIZED = new ResponseType('UNAUTHORIZED');

/**
* The gateway response when a payload is of an unsupported media type, if strict passthrough behavior is enabled.
*/
public static readonly UNSUPPORTED_MEDIA_TYPE = new ResponseType('UNSUPPORTED_MEDIA_TYPE');

/**
* The gateway response when a request is blocked by AWS WAF.
*/
public static readonly WAF_FILTERED = new ResponseType('WAF_FILTERED');

/** A custom response type to suppport future cases. */
public static of(type: string): ResponseType {
return new ResponseType(type.toUpperCase());
}

/**
* Valid value of response type.
*/
public readonly responseType: string;

private constructor(type: string) {
this.responseType = type;
}

}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-apigateway/lib/index.ts
Expand Up @@ -20,6 +20,7 @@ export * from './base-path-mapping';
export * from './cors';
export * from './authorizers';
export * from './access-log';
export * from './gateway-response';

// AWS::ApiGateway CloudFormation Resources:
export * from './apigateway.generated';
Expand Down
11 changes: 11 additions & 0 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Expand Up @@ -6,6 +6,7 @@ import { CfnAccount, CfnRestApi } from './apigateway.generated';
import { CorsOptions } from './cors';
import { Deployment } from './deployment';
import { DomainName, DomainNameOptions } from './domain-name';
import { GatewayResponse, GatewayResponseOptions } from './gateway-response';
import { Integration } from './integration';
import { Method, MethodOptions } from './method';
import { Model, ModelOptions } from './model';
Expand Down Expand Up @@ -390,6 +391,16 @@ export class RestApi extends Resource implements IRestApi {
this.methods.push(method);
}

/**
* Adds a new gateway response.
*/
public addGatewayResponse(id: string, options: GatewayResponseOptions): GatewayResponse {
return new GatewayResponse(this, id, {
restApi: this,
...options,
});
}

/**
* Performs validation of the REST API.
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-apigateway/package.json
Expand Up @@ -106,6 +106,7 @@
"exclude": [
"from-method:@aws-cdk/aws-apigateway.Resource",
"duration-prop-type:@aws-cdk/aws-apigateway.QuotaSettings.period",
"duration-prop-type:@aws-cdk/aws-apigateway.ResponseType.INTEGRATION_TIMEOUT",
"from-method:@aws-cdk/aws-apigateway.ApiKey",
"ref-via-interface:@aws-cdk/aws-apigateway.ApiKeyProps.resources",
"props-physical-name:@aws-cdk/aws-apigateway.DeploymentProps",
Expand All @@ -116,6 +117,7 @@
"props-physical-name-type:@aws-cdk/aws-apigateway.StageProps.stageName",
"props-physical-name:@aws-cdk/aws-apigateway.BasePathMappingProps",
"props-physical-name:@aws-cdk/aws-apigateway.LambdaRestApiProps",
"props-physical-name:@aws-cdk/aws-apigateway.GatewayResponseProps",
"construct-interface-extends-iconstruct:@aws-cdk/aws-apigateway.IModel",
"resource-interface-extends-resource:@aws-cdk/aws-apigateway.IModel",
"docs-public-apis:@aws-cdk/aws-apigateway.JsonSchema.definitions",
Expand Down

0 comments on commit b0a65c1

Please sign in to comment.