【问题标题】:How get path params in CDK + APIGateway + Lambda如何在 CDK + APIGateway + Lambda 中获取路径参数
【发布时间】:2021-10-12 20:06:56
【问题描述】:

所以,事实证明我一直都拥有它,但我错误地注销了它。我一直在做一个 Object.keys(event).forEach 和控制台记录每个键和值。我猜这没有显示值,因为它是一个嵌套对象。根据@robC3 的回答,使用 JSON.stringify 可以正确显示所有嵌套对象和值,而且也更容易! TL;DR 只需在网关路径中使用大括号,它们就会出现在 event.pathParameters.whateverYouCalledThem 中

我习惯于表达你只需在你的路线中写/stuff/:things 然后req.params.things 在你的处理程序中用于“东西”的地方。

我正在努力在 CDK 中获得相同的基本功能。我有一个名为“api”的 RestAPI 和类似的资源......

const api = new apigateway.RestApi(this, "image-cache-api", { //options })
const stuff = api.root.addResource("stuff")
const stuffWithId = get.addResource("{id}")
stuffWithId.addMethod("GET", new apigateway.LambdaIntegration(stuffLambda, options))

然后我部署函数并在https://<api path>/stuff/1234调用它

然后在我的 lambda 中检查 event.pathParameters 是这样的:{id: undefined}

我查看了事件对象,唯一能看到 1234 的地方是路径 /stuff/1234,虽然我可以从中解析出来,但我确定这不是它应该的样子工作。

:/

我在谷歌搜索时发现的大部分内容都提到了“映射模板”。对于这样一个常见的用例来说,这似乎过于复杂,所以我一直在努力假设会有某种默认映射。现在我开始认为没有。我真的必须指定一个映射模板才能访问路径参数吗?如果是这样,它应该放在我的 CDK 堆栈代码中的什么位置?

我尝试了以下...

stuffWithId.addMethod("GET", new apigateway.LambdaIntegration(stuffLambda, {
    requestTemplate: {
        "id": "$input.params('id')",
    }        
}))

但出现错误...

error TS2559: Type '{ requestTemplate: { id: string; }; }' has no properties in common with type 'LambdaIntegrationOptions'.

我很困惑是否需要 requestTemplate、requestParametes 或其他东西,因为到目前为止我发现的所有示例都是针对控制台而不是 CDK。

【问题讨论】:

    标签: amazon-web-services aws-lambda aws-api-gateway


    【解决方案1】:

    这很好用,当你在浏览器中测试它时,你可以看到完整路径、路径参数、查询参数等在事件结构中的位置。

    // lambdas/handler.ts

    // This code uses @types/aws-lambda for typescript convenience.
    // Build first, and then deploy the .js handler.
    
    import { APIGatewayProxyHandler, APIGatewayProxyResult } from 'aws-lambda';
    
    export const main: APIGatewayProxyHandler = async (event, context, callback) => {
        return <APIGatewayProxyResult> {
            body: JSON.stringify([ event, context ], null, 4),
            statusCode: 200,
        };
    }
    

    //apig-lambda-proxy-demo-stack.ts

    import * as path from 'path';
    import { aws_apigateway, aws_lambda, Stack, StackProps } from 'aws-cdk-lib';
    import { Construct } from 'constructs';
    
    export class ApigLambdaProxyDemoStack extends Stack {
      constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);
    
        const stuffLambda = new aws_lambda.Function(this, 'stuff-lambda', {
            code: aws_lambda.Code.fromAsset(path.join('dist', 'lambdas')),
            handler: 'handler.main',
            runtime: aws_lambda.Runtime.NODEJS_14_X,
        });
    
        const api = new aws_apigateway.RestApi(this, 'image-cache-api');
    
        const stuff = api.root.addResource('stuff');
        const stuffWithId = stuff.addResource('{id}');
        stuffWithId.addMethod('GET', new aws_apigateway.LambdaIntegration(stuffLambda));
      }
    }
    

    此示例查询:

    https://[id].execute-api.[region].amazonaws.com/prod/stuff/1234?q1=foo&q2=bar

    给出这个回应(摘录):

    如果您想在 API 中的某个位置处理任意路径,您需要探索IResource.addProxy() CDK 方法。例如,

    api.root.addProxy({
        defaultIntegration: new aws_apigateway.LambdaIntegration(stuffLambda),
    });
    

    这会在示例中的 API 根目录中创建一个 {proxy+} 资源,并将所有请求转发到 lambda。您可以在同一个处理程序中处理它们,而不是在 API Gateway 中配置每个端点。

    【讨论】:

      【解决方案2】:

      首先要注意的是,所有使用 LambdaIntegration 模块的 cdk 实际上都必须是 Post - 使用 LambdaIntegration 的 Get 方法在您向 Lambda 发送数据时不起作用。如果你想专门做一个 get ,你必须在 api 中为它编写自定义方法。

      现在,我只在 Python 中做过这个,但希望你能明白:

      my_rest_api = apigateway.RestApi(
              self, "MyAPI",
              retain_deployments=True,
              deploy_options=apigateway.StageOptions(
                  logging_level=apigateway.MethodLoggingLevel.INFO,
                  stage_name="Dev
              )
          )
      
      
      a_resource = apigateway.Resource(
              self, "MyResource",
              parent=my_rest_api.root,
              path_part="Stuff"
          )
      
      my_method = apigateway.Method(
              self, "MyMethod",
              http_method="POST",
              resource=quoting_resource,
              integration=apigateway.AwsIntegration(
                  service="lambda",
                  integration_http_method="POST",
                  path="my:function:arn"
              )
          )
      

      您的 Resource 构造定义了您的路径 - 如果您希望在每个级别都有方法,您可以将多个资源链接在一起,或者将它们全部放在 path_part 中 - 这样您就可以定义 resourceA,并将其用作 resourceB 中的父级- 这会让你 resourceAPathPart/resourceBPathPart/ 访问你的 lambda。

      或者您可以将它们全部放在 resourceA 中,使用 path_part = stuff/path/ect

      我在这里使用了 AwsIntegration 方法而不是 LambdaIntegration,因为在完整代码中,我使用阶段变量来根据我所处的阶段动态选择不同的 lambda,但效果相当相似

      【讨论】:

      • 感谢您的建议,但我不明白这如何帮助解决我的问题。我的路径不是固定的。我需要获取一个路径变量,例如如果 URL 是 example.com/food/sausages 我需要“香肠”,但如果是 example.com/food/beans 我需要“beans”。
      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2021-04-24
      • 2015-12-03
      • 2019-05-27
      • 1970-01-01
      • 2020-05-28
      • 2023-01-04
      • 2021-07-10
      相关资源
      最近更新 更多