如何在CDK + APIGateway + Lambda中获取路径参数

tec*_*oke 6 amazon-web-services aws-lambda aws-api-gateway

So, turns out I had it all along but I was logging it out incorrectly. I had been doing a Object.keys(event).forEach and console logging each key and value. I guess this didn't display the value as it's a nested object. Using JSON.stringify, as per @robC3's answer shows all the nested objects and values properly and is easier too! TL;DR just use curly braces in your gateway paths and they will be present in event.pathParameters.whateverYouCalledThem

I'm used to express land where you just write /stuff/:things in your route and then req.params.things becomes available in your handler for 'stuff'.

I'm struggling to get the same basic functionality in CDK. I have a RestAPI called 'api' and resources like so...

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))
Run Code Online (Sandbox Code Playgroud)

Then I deploy the function and call it at https://<api path>/stuff/1234

Then in my lambda I check event.pathParameters and it is this: {id: undefined}

I've had a look through the event object and the only place I can see 1234 is in the path /stuff/1234 and while I could just parse it out of that I'm sure that's not how it's supposed to work.

:/

Most of the things I have turned up while googling mention "mapping templates". That seems overly complicated for such a common use case so I had been working to the assumption there would be some sort of default mapping. Now I'm starting to think there isn't. Do I really have to specify a mapping template just to get access to path params and, if so, where should it go in my CDK stack code?

I tried the following...

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

But got the error...

error TS2559: Type '{ requestTemplate: { id: string; }; }' has no properties in common with type 'LambdaIntegrationOptions'.
Run Code Online (Sandbox Code Playgroud)

I'm pretty confused as to whether I need requestTemplate, requestParametes, or something else entirely as all the examples I have found so far are for the console rather than CDK.

rob*_*b3c 11

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

// 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,
    };
}
Run Code Online (Sandbox Code Playgroud)

// 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));
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例查询:

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

给出了这个回应(摘录):

示例 API Gateway 测试 lambda 响应 JSON

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

api.root.addProxy({
    defaultIntegration: new aws_apigateway.LambdaIntegration(stuffLambda),
});
Run Code Online (Sandbox Code Playgroud)

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


lyn*_*fox 0

首先要注意的是,所有使用 LambdaIntegration 模块的 cdk 实际上都必须是 Post - Get 方法,当您将数据发送到 Lambda 时,LambdaIntegration 的 Get 方法不起作用。如果你想专门进行 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"
        )
    )
Run Code Online (Sandbox Code Playgroud)

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

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

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