aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.35k stars 3.77k forks source link

aws-apigateway: requestValidatorOptions does not create validator #29834

Open anneadb opened 2 months ago

anneadb commented 2 months ago

Describe the bug

I am trying to add a request validator to my Lambda proxy API. I am setting requestValidatorOptions in defaultMethodOptions but no validator is being created and added to the methods. In the UI/console I can add a validation to the "ANY" method which is automatically created as part of LambdaRestApi.

Is there another way to add the validator to the proxy?

Expected Behavior

Validator is created and added to all methods.

Current Behavior

The cloudformation template shows the RequestParameters but no validator. Adding requestValidatorOptions is not recognized as a change during deployment.

Reproduction Steps

Create an api gateway using LambdaRestApi:

new apigateway.LambdaRestApi(this, "LambdaRestApi", {
      restApiName: `${env.project}-${subProjectName}-${env.deployer}`,
      handler: lambdaFunction,
      deployOptions: {
        loggingLevel: apigateway.MethodLoggingLevel.INFO,
        accessLogDestination: new apigateway.LogGroupLogDestination(logGroup),
        accessLogFormat: apigateway.AccessLogFormat.jsonWithStandardFields(),
      },
      defaultMethodOptions: {
        apiKeyRequired: true,
        requestParameters: {
          "method.request.querystring.name": true,
          "method.request.querystring.env": false,
        },
        requestValidatorOptions: {
          requestValidatorName: "DefaultValidator",
          validateRequestParameters: true,
        },
      },
      endpointTypes: [apigateway.EndpointType.REGIONAL],
    })

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.122.0

Framework Version

No response

Node.js Version

v20.10.0

OS

macOS 14.4.1

Language

TypeScript

Language Version

No response

Other information

"AWS::ApiGateway::Method" from template.json:

"ApiGatewaySetupLambdaRestApiproxyANYF9A30FCD": {
   "Type": "AWS::ApiGateway::Method",
   "Properties": {
    "ApiKeyRequired": true,
    "AuthorizationType": "NONE",
    "HttpMethod": "ANY",
    "Integration": {
     "IntegrationHttpMethod": "POST",
     "Type": "AWS_PROXY",
     "Uri": {
      "Fn::Join": [
       "",
       [
        "arn:aws:apigateway:eu-central-1:lambda:path/2015-03-31/functions/",
        {
         "Fn::GetAtt": [
          "LambdaSetuplambdaE27E4408",
          "Arn"
         ]
        },
        "/invocations"
       ]
      ]
     }
    },
    "RequestParameters": {
     "method.request.querystring.name": true,
     "method.request.querystring.env": false
    },
    "ResourceId": {
     "Ref": "ApiGatewaySetupLambdaRestApiproxyD538D22D"
    },
    "RestApiId": {
     "Ref": "ApiGatewaySetupLambdaRestApi68D08033"
    }
   },
   "Metadata": {
    "aws:cdk:path": "MyStack/ApiGatewaySetup/LambdaRestApi/Default/{proxy+}/ANY/Resource"
   }
  },
khushail commented 1 month ago

Hi @anneadb , thanks for reaching out.

You could try creating a resource and then use .addMethod like this to set the requestValidatorOptions{..}. Here is the article for reference - https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.RequestValidatorOptions.html.

Here is snippet of successful implementation of the requestValidator with LambdarestApi-

Screenshot 2024-05-06 at 6 57 43 PM

Please feel free to reach out if this does not work for you.

anneadb commented 1 month ago

Hi @khushail , do you have proxy (https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html#proxy) set to True? Because I thought that that was not compatible with adding methods.

khushail commented 1 month ago

Hi @khushail , do you have proxy (https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html#proxy) set to True? Because I thought that that was not compatible with adding methods.

Sharing the complete code. I kept proxy:false for adding methods -


import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigateway';
import { ApiGateway } from 'aws-cdk-lib/aws-events-targets';

export class RequestValidator2Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const myLambda = new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromInline('print("Hello, CDK!") ')
    });

    const api = new apigw.LambdaRestApi(this,'ApiGateway',{
      restApiName: 'RequestValidatorApi',
        handler: myLambda,
        proxy: false
      }
    );

    const responseModel = api.addModel('ResponseModel', {
      contentType: 'application/json',
      modelName: 'ResponseModel',
      schema: { 'schema': apigw.JsonSchemaVersion.DRAFT4, 'title': 'pollResponse', 'type': apigw.JsonSchemaType.OBJECT, 'properties': { 'message': { 'type': apigw.JsonSchemaType.STRING } } }
    });

    const errorResponseModel = api.addModel('ErrorResponseModel', {
      contentType: 'application/json',
      modelName: 'ErrorResponseModel',
      schema: { 'schema': apigw.JsonSchemaVersion.DRAFT4, 'title': 'errorResponse', 'type': apigw.JsonSchemaType.OBJECT, 'properties': { 'message': { 'type': apigw.JsonSchemaType.STRING } } }
    });

    const resource = api.root.addResource('books');
    const getBookIntergration = new apigw.LambdaIntegration(myLambda);

    resource.addMethod('GET', getBookIntergration, {
      requestParameters: {
        'method.request.querystring.who': true
      },
      // we can set request validator options like below
      requestValidatorOptions: {
        requestValidatorName: 'requestValidator',
        validateRequestBody: true,
        validateRequestParameters: true
      },
      methodResponses: [
        {
          // Successful response from the integration
          statusCode: '200',

          responseParameters: {
            'method.response.header.Content-Type': true,
            'method.response.header.Access-Control-Allow-Origin': true,
            'method.response.header.Access-Control-Allow-Credentials': true
          },
          responseModels: {
            'application/json': responseModel
          }
        },
        {
          statusCode: '400',
          responseParameters: {
            'method.response.header.Content-Type': true,
            'method.response.header.Access-Control-Allow-Origin': true,
            'method.response.header.Access-Control-Allow-Credentials': true
          },
          responseModels: {
            'application/json': errorResponseModel
          }
        }
      ]
    });

  }
}

`

anneadb commented 1 month ago

Thank you for the entire code. Then sadly this is not an option for me because I specifically want to keep the proxy functionality.