Search code examples
aws-cdk

Request Validation in AWS CDK


My efforts to enable request validation through cdk with typescript have not worked. Having worked around some known bus of the environment, I arrived at this:

  const req = new apiGateway.RequestValidator(this, lambdaName, {
    restApi: this._api,
    requestValidatorName: lambdaName,
    validateRequestBody: false,
    validateRequestParameters: true
  });
  // this._methodOptions.requestValidator = {},
  this._methodOptions.requestValidator = req;

The error I recieve is TypeError: Cannot read property 'children' of undefined.

TypeError: Cannot read property 'children' of undefined
    at synthNestedAssemblies (proj\cdk\node_modules\@aws-cdk\core\lib\private\synthesis.ts:50:33)
    at synthNestedAssemblies (proj\cdk\node_modules\@aws-cdk\core\lib\private\synthesis.ts:54:7)
    at synthNestedAssemblies (proj\cdk\node_modules\@aws-cdk\core\lib\private\synthesis.ts:54:7)
    at synthNestedAssemblies (proj\cdk\node_modules\@aws-cdk\core\lib\private\synthesis.ts:54:7)
    at Object.synthesize (proj\cdk\node_modules\@aws-cdk\core\lib\private\synthesis.ts:14:3)
    at App.synth (proj\cdk\node_modules\@aws-cdk\core\lib\stage.ts:188:23)
    at process.App.process.once (proj\cdk\node_modules\@aws-cdk\core\lib\app.ts:123:45)
    at Object.onceWrapper (events.js:277:13)
    at process.emit (events.js:189:13)
    at process.EventEmitter.emit (domain.js:441:20)

I suspect there are some issues under the hood still. Anyone know how to get this working?

Edit: Adding info on how _methodOptions was built up

  private _reqValidatorQueryStrHeaders: apiGateway.RequestValidator;


  // Create validators to use in method options
  private _initValidators() {
    this._reqValidatorAll = this._api.addRequestValidator("validate-request-all", {
      requestValidatorName: "req-validator-all",
      validateRequestBody: true,
      validateRequestParameters: true,
    });

    this._reqValidatorBody = this._api.addRequestValidator("validate-request-body", {
      requestValidatorName: "req-validator-body",
      validateRequestBody: true,
      validateRequestParameters: true,
    });

    this._reqValidatorQueryStrHeaders = this._api.addRequestValidator("validate-request-query-etc", {
      requestValidatorName: "req-validator-query-and-headers",
      validateRequestBody: true,
      validateRequestParameters: true,
    });
  }

 private _initDefMethodOptions(uniqueId: string) {
    this._defMethodOptions = {

  // Method Request Quadrant:
  // ------------------------
    
    // Cognito Auth
      authorizer: {authorizerId: this._auth.ref},
      authorizationType: apiGateway.AuthorizationType.COGNITO,

    // Request Validation - works *with* requestParameters & requestModels 
      requestValidator: {
        Name: uniqueId 
      },
      requestParameters: {
        'method.request.querystring.unused': false // required True
      },

      // apiKeyRequired: false,
  
  // Method Response Quadrant:
  // ------------------------
      methodResponses: [
        {
          // Successful response from the integration
          statusCode: '200',
          // Define what parameters are allowed or not
          responseParameters: {
            'method.response.header.Access-Control-Allow-Origin': true,
            // 'method.response.header.Content-Type': true,
            // 'method.response.header.Access-Control-Allow-Credentials': true // don't need this with cognito credentials...
          },
          // // Validate the schema on the response
          // responseModels: {
          //   'application/json': responseModel
          // }
        },
        {
          // Same thing for the error responses
          statusCode: '400',
          responseParameters: {    //is this necessary with the api wide default set above?         
            'method.response.header.Access-Control-Allow-Origin': true,
          //   'method.response.header.Content-Type': true,
          //   'method.response.header.Access-Control-Allow-Credentials': true
          },
          // responseModels: {
          //   'application/json': errorResponseModel
          // }
        },
        {
          statusCode: '403',
          responseParameters: {
            'method.response.header.Access-Control-Allow-Origin': true,
          },
        },
        {
          statusCode: '500',
          responseParameters: {
            'method.response.header.Access-Control-Allow-Origin': true,
          },
        }
      ]
    };
    return this._defMethodOptions;
  }


  /* In other function */
  this._methodOptions = this._initDefMethodOptions(lambdaName);
  let queryList : string[] = options.reqParams;
    if (typeof (queryList) !== "undefined") {
      // this._methodOptions.requestValidator = { Name: lambdaName };                      // does nothing. Wrong class. 
      // this._methodOptions.requestValidator = this._getRequestValidator(lambdaName);  // crashes!


      // Using the fix from answer: 
      this._methodOptions.requestValidator = this._reqValidatorQueryStrHeaders;

Solution

  • We can pass in validator to Method Options.

    /**
     * Basic Rest Api
     */
    const myRestApi = new apigateway.RestApi(this, "rest-api", {});
    
    /**
     * A Validator
     */
    const myValidator = myRestApi.addRequestValidator("validate-request", {
      requestValidatorName: "my-request-validator",
      validateRequestBody: true,
      validateRequestParameters: true,
    });
    
    /**
     * Simple Method attaching the validator.
     */
    const postMethod = myRestApi.root.addMethod(
      "POST",
      new apigw.MockIntegration(),
      {
        requestValidator: myValidator,
      }
    );