diff --git a/packages/@aws-cdk/aws-apigateway/README.md b/packages/@aws-cdk/aws-apigateway/README.md index 34d414c0f9f36..05f44abc54862 100644 --- a/packages/@aws-cdk/aws-apigateway/README.md +++ b/packages/@aws-cdk/aws-apigateway/README.md @@ -297,18 +297,17 @@ const errorResponseModel = api.addModel('ErrorResponseModel', { And reference all on your method definition. ```ts -// If you want to define parameter mappings for the request, you need a validator -const validator = api.addRequestValidator('DefaultValidator', { - validateRequestBody: false, - validateRequestParameters: true -}); resource.addMethod('GET', integration, { // We can mark the parameters as required requestParameters: { 'method.request.querystring.who': true }, - // We need to set the validator for ensuring they are passed - requestValidator: validator, + // we can set request validator options like below + requestValidatorOptions: { + requestValidatorName: 'test-validator', + validateRequestBody: true, + validateRequestParameters: false + } methodResponses: [ { // Successful response from the integration @@ -340,6 +339,9 @@ resource.addMethod('GET', integration, { }); ``` +Specifying `requestValidatorOptions` automatically creates the RequestValidator construct with the given options. +However, if you have your RequestValidator already initialized or imported, use the `requestValidator` option instead. + #### Default Integration and Method Options The `defaultIntegration` and `defaultMethodOptions` properties can be used to diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 9b43cec12d593..8120823d410fb 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -5,7 +5,7 @@ import { ConnectionType, Integration } from './integration'; import { MockIntegration } from './integrations/mock'; import { MethodResponse } from './methodresponse'; import { IModel } from './model'; -import { IRequestValidator } from './requestvalidator'; +import { IRequestValidator, RequestValidatorOptions } from './requestvalidator'; import { IResource } from './resource'; import { RestApi } from './restapi'; import { validateHttpMethod } from './util'; @@ -73,6 +73,8 @@ export interface MethodOptions { /** * The ID of the associated request validator. + * Only one of `requestValidator` or `requestValidatorOptions` must be specified. + * @default - No default validator */ readonly requestValidator?: IRequestValidator; @@ -83,6 +85,13 @@ export interface MethodOptions { * @default - no authorization scopes */ readonly authorizationScopes?: string[] + + /** + * Request validator options to create new validator + * Only one of `requestValidator` or `requestValidatorOptions` must be specified. + * @default - No default validator + */ + readonly requestValidatorOptions?: RequestValidatorOptions; } export interface MethodProps { @@ -160,7 +169,7 @@ export class Method extends Resource { integration: this.renderIntegration(props.integration), methodResponses: this.renderMethodResponses(options.methodResponses), requestModels: this.renderRequestModels(options.requestModels), - requestValidatorId: options.requestValidator ? options.requestValidator.requestValidatorId : undefined, + requestValidatorId: this.requestValidatorId(options), authorizationScopes: options.authorizationScopes ?? defaultMethodOptions.authorizationScopes, }; @@ -302,6 +311,20 @@ export class Method extends Resource { return models; } + + private requestValidatorId(options: MethodOptions): string | undefined { + if (options.requestValidator && options.requestValidatorOptions) { + throw new Error(`Only one of 'requestValidator' or 'requestValidatorOptions' must be specified.`); + } + + if (options.requestValidatorOptions) { + const validator = this.restApi.addRequestValidator('validator', options.requestValidatorOptions); + return validator.requestValidatorId; + } + + // For backward compatibility + return options.requestValidator?.requestValidatorId; + } } export enum AuthorizationType { diff --git a/packages/@aws-cdk/aws-apigateway/test/test.method.ts b/packages/@aws-cdk/aws-apigateway/test/test.method.ts index f4c5052e1ec40..7c898c11b606b 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.method.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.method.ts @@ -802,6 +802,84 @@ export = { AuthorizationScopes: ABSENT })); + test.done(); + }, + + 'method has a request validator with provided properties'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + + // WHEN + new apigw.Method(stack, 'method-man', { + httpMethod: 'GET', + resource: api.root, + options: { + requestValidatorOptions: { + requestValidatorName: 'test-validator', + validateRequestBody: true, + validateRequestParameters: false + } + } + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::RequestValidator', { + RestApiId: stack.resolve(api.restApiId), + ValidateRequestBody: true, + ValidateRequestParameters: false, + Name: 'test-validator' + })); + + test.done(); + }, + + 'method does not have a request validator'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + + // WHEN + new apigw.Method(stack, 'method-man', { + httpMethod: 'GET', + resource: api.root + }); + + // THEN + expect(stack).to(haveResource('AWS::ApiGateway::Method', { + RequestValidatorId: ABSENT + })); + + test.done(); + }, + + 'method does not support both request validator and request validator options'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigw.RestApi(stack, 'test-api', { deploy: false }); + const validator = api.addRequestValidator('test-validator1', { + validateRequestBody: true, + validateRequestParameters: false + }); + + // WHEN + const methodProps = { + httpMethod: 'GET', + resource: api.root, + options: { + requestValidatorOptions: { + requestValidatorName: 'test-validator2', + validateRequestBody: true, + validateRequestParameters: false + }, + requestValidator: validator + } + }; + + // THEN + test.throws(() => new apigw.Method(stack, 'method', methodProps), + /Only one of 'requestValidator' or 'requestValidatorOptions' must be specified./); + test.done(); } };