AWS CDK如何根据OpenApi规范创建由Lambda支持的API网关? [英] AWS CDK how to create an API Gateway backed by Lambda from OpenApi spec?

查看:165
本文介绍了AWS CDK如何根据OpenApi规范创建由Lambda支持的API网关?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用AWS CDK定义API网关和APIG将代理的lambda.

OpenAPI规范支持Swagger规范的x-amazon-apigateway-integration自定义扩展(详细

Q1.这似乎是个鸡与蛋的问题,以上是实现此目的的唯一方法吗?

我尝试使用 SpecRestApi CDK构造.该文档指出:

在此方法中创建的所有方法默认使用的集成 除非指定了集成,否则API.

这似乎应该能够使用CDK规范中定义的lambda定义默认集成,因此所有方法都可以使用此集成,而无需事先知道lambda的uri.

因此,我尝试了这一点:

SingletonFunction myLambda = ...

SpecRestApi openapiRestApi = SpecRestApi.Builder.create(this, "MyApi")
                        .restApiName("MyApi")
                        .apiDefinition(ApiDefinition.fromAsset("openapi.yaml"))
                        .defaultIntegration(LambdaIntegration.Builder.create(myLambda)
                                    .proxy(false)
                                    .build())
                        .deploy(true)
                        .build();

openapi.yaml中定义的OpenAPI规范不包含x-amazon-apigateway-integration节;它只有一个在标准OpenApi 3规范中定义的GET方法.

但是,当我尝试部署它时,出现错误:

No integration defined for method (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 56113150-1460-4ed2-93b9-a12618864582)

这似乎是一个错误,所以我在这里在这里提交了./p>

Q2.如何使用CDK定义API网关和Lambda,并通过OpenAPI规范将两者连接在一起?

解决方案

此处 a>并提出解决方法.

我使用 https://github.com/spullara/mustache.java 进行解析我的OpenAPI规范文件,并替换其中引用API网关的调用ARN(其本身引用Lambda ARN)的模板值.

Map<String, Object> variables = new HashMap<>();
variables.put("restapi-lambda", String.format("arn:aws:apigateway:%s:lambda:path/2015-03-31/functions/%s/invocations", props.getEnv().getRegion(), myLambda.getFunctionArn()));

Writer writer = new StringWriter();
MustacheFactory mf = new DefaultMustacheFactory();

Object openapiSpecAsObject;
try (Reader reader = new FileReader(new File("myapi.yaml"))) {
    Mustache mustache = mf.compile(reader, "OAS");
    mustache.execute(writer, scopes);
    writer.flush();

    ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
    openapiSpecAsObject = yamlMapper.readValue(writer.toString(), Object.class);

}

SpecRestApi openapiRestApi = SpecRestApi.Builder.create(this, "MyRestApi")
                                                .restApiName("MyRestApi")
                                                .apiDefinition(ApiDefinition.fromInline(openapiSpecAsObject))
                                                .deploy(true)
                                                .build();

请注意,props是引用Stack道具的变量,而myLambda是引用SingletonFunction的变量.

我的OpenAPI规范如下(已删除标题和模型部分):

paths:
  /items:
    get:
      summary: List all items.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ItemList'
      x-amazon-apigateway-integration:
        uri: "{{restapi-lambda}}"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        type: "aws_proxy"

还请注意,当我授予API网关权限来像这样调用lambda时:

myLambda.grantInvoke(ServicePrincipal.Builder.create("apigateway.amazonaws.com")
                                              .build());

我仍然收到500错误,并且在日志中可以看到对Lambda函数的权限无效"错误消息.如果我向Lambda添加权限,如下所示:

myLambda.addPermission("PermitAPIGInvocation", Permission.builder()
                                  .action("lambda:InvokeFunction")
                                  .principal(ServicePrincipal.Builder.create("apigateway.amazonaws.com")
                                     .build())
                                  .sourceArn(openapiRestApi.arnForExecuteApi())
                                  .build());

然后,在权限生效之前,我目前需要重新部署API.我还在努力避免这种情况.

I want to use AWS CDK to define an API Gateway and a lambda that the APIG will proxy to.

The OpenAPI spec supports a x-amazon-apigateway-integration custom extension to the Swagger spec (detailed here), for which an invocation URL of the lambda is required. If the lambda is defined in the same stack as the API, I don't see how to provide this in the OpenAPI spec. The best I can think of would be to define one stack with the lambda in, then get the output from this and run sed to do a find-and-replace in the OpenAPI spec to insert the uri, then create a second stack with this modified OpenAPI spec.

Example:

  /items:
    post:
      x-amazon-apigateway-integration:
        uri: "arn:aws:apigateway:eu-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-2:123456789012:function:MyStack-SingletonLambda4677ac3018fa48679f6-B1OYQ50UIVWJ/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        type: "aws_proxy"

Q1. This seems like a chicken-and-egg problem, is the above the only way to do this?

I tried to use the defaultIntegration property of the SpecRestApi CDK construct. The documentation states:

An integration to use as a default for all methods created within this API unless an integration is specified.

This seems like a should be able to define a default integration using a lambda defined in the CDK spec and therefore have all methods use this integration, without needing to know the uri of the lambda in advance.

Thus I tried this:

SingletonFunction myLambda = ...

SpecRestApi openapiRestApi = SpecRestApi.Builder.create(this, "MyApi")
                        .restApiName("MyApi")
                        .apiDefinition(ApiDefinition.fromAsset("openapi.yaml"))
                        .defaultIntegration(LambdaIntegration.Builder.create(myLambda)
                                    .proxy(false)
                                    .build())
                        .deploy(true)
                        .build();

The OpenAPI spec defined in openapi.yaml does not include a x-amazon-apigateway-integration stanza; it just has a single GET method defined within a standard OpenApi 3 specification.

However, when I try to deploy this, I get an error:

No integration defined for method (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 56113150-1460-4ed2-93b9-a12618864582)

This seems like a bug, so I filed one here.

Q2. How do I define an API Gateway and Lambda using CDK and wire the two together via an OpenAPI spec?

解决方案

It looks like what I'm after is tracked by this CDK issue. In the meantime, I was guided by the comment on that issue here and came up with a workaround.

I used https://github.com/spullara/mustache.java to parse my OpenAPI spec file and replace template values in it that referenced the invocation ARN of the API gateway (that itself references the Lambda ARN).

Map<String, Object> variables = new HashMap<>();
variables.put("restapi-lambda", String.format("arn:aws:apigateway:%s:lambda:path/2015-03-31/functions/%s/invocations", props.getEnv().getRegion(), myLambda.getFunctionArn()));

Writer writer = new StringWriter();
MustacheFactory mf = new DefaultMustacheFactory();

Object openapiSpecAsObject;
try (Reader reader = new FileReader(new File("myapi.yaml"))) {
    Mustache mustache = mf.compile(reader, "OAS");
    mustache.execute(writer, scopes);
    writer.flush();

    ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
    openapiSpecAsObject = yamlMapper.readValue(writer.toString(), Object.class);

}

SpecRestApi openapiRestApi = SpecRestApi.Builder.create(this, "MyRestApi")
                                                .restApiName("MyRestApi")
                                                .apiDefinition(ApiDefinition.fromInline(openapiSpecAsObject))
                                                .deploy(true)
                                                .build();

Note that props is a variable that refers to the Stack props and myLambda is a reference to a SingletonFunction.

My OpenAPI spec looks like this (header and model sections removed):

paths:
  /items:
    get:
      summary: List all items.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ItemList'
      x-amazon-apigateway-integration:
        uri: "{{restapi-lambda}}"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        type: "aws_proxy"

Also note that when I granted API Gateway permissions to invoke the lambda like this:

myLambda.grantInvoke(ServicePrincipal.Builder.create("apigateway.amazonaws.com")
                                              .build());

I still get a 500 error and in the logs I can see an "Invalid permissions on Lambda function" error message. If I add permissions to the Lambda, like this:

myLambda.addPermission("PermitAPIGInvocation", Permission.builder()
                                  .action("lambda:InvokeFunction")
                                  .principal(ServicePrincipal.Builder.create("apigateway.amazonaws.com")
                                     .build())
                                  .sourceArn(openapiRestApi.arnForExecuteApi())
                                  .build());

then I currently need to redeploy the API before the permissions take effect. I'm still working through how to avoid this.

这篇关于AWS CDK如何根据OpenApi规范创建由Lambda支持的API网关?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆