web-dev-qa-db-ja.com

AWS CDK openapi specからLambdaによってバックアップされたAPIゲートウェイを作成する方法は?

APIゲートウェイとApigがプロキシするとラムダを定義するには、AWS CDKを使用します。

OpenAPI SPECは、Swagger Specへのx-Amazon-apigateway-integrationカスタム拡張をサポートしています(詳細 ここで )、Lambdaの呼び出しURLが必要です。ラムダがAPIと同じスタックで定義されている場合は、OpenAPI仕様でこれを提供する方法はわかりません。私が考えることができる最善のことは、ラムダを持つ1つのスタックを定義し、これから出力を取得し、sedを実行してOpenAPI仕様の検索および置換を実行してURIを挿入してから作成します。この修正されたOpenAPI仕様を持つ2番目のスタック。

例:

  /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。これは鶏肉と卵の問題のように思えます、これを行う唯一の方法は?

defaultIntegrationspecrestapi cdk構文のプロパティを使用しようとしました。ドキュメントの状態

統合が指定されていない限り、このAPI内で作成されたすべてのメソッドのデフォルトとして使用する統合。

これは、CDK仕様で定義されているラムダを使用してデフォルトの統合を定義できるように見えます。したがって、すべての方法では、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)

これはバグのように思えます、それで私は1を出願しました ここ

Q2。 CDKを使用してAPIゲートウェイとラムダを定義し、OpenAPI仕様を介して2つを一緒に配線しますか?

6
John

私はここでの他の回答よりも少し単純であるソリューションが段階的な変数または複数の展開を必要としないというソリューションを思い付きました。

まず、_x-Amazon-apigateway-integration_のuriを_${API_LAMBDA_ARN}_のような変数に設定し、この例のように同じtypehttpMethodを使用します。

_[...]
  "paths": {
    "/pets": {
      "get": {
        "summary": "List all pets",
        "responses": {
          [...]
        },
        "x-Amazon-apigateway-integration": {
          "uri": "${API_LAMBDA_ARN}",
          "type": "AWS_PROXY",
          "httpMethod": "POST",
        }
      }
    }
  },
[...]
_

次に、この構成(または同等のタイプの実装)を使用してビルド時に変数を置き換え、OpenAPI文書に基づいてAPI Gateway HTTP APIを作成することができます。

_from aws_cdk import (
    core,
    aws_iam as iam,
    aws_lambda as _lambda,
    aws_apigatewayv2 as apigateway
)


class OpenApiLambdaStack(core.Stack):
    def __init__(
        self, scope: core.Construct, construct_id: str, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # function that handles api request(s)
        api_lambda = _lambda.Function([...])

        # read openapi document
        with open("openapi.json", "r") as json_file:
            content = json_file.read()
        # replace the variable by the lambda functions arn
        content = content.replace("${API_LAMBDA_ARN}", api_lambda.function_arn)
        openapi = json.loads(content)

        # create apigateway
        http_api = apigateway.HttpApi(self, "OpenApiLambdaGateway")
        # use escape hatches to import OpenAPI Document
        # see: https://docs.aws.Amazon.com/cdk/latest/guide/cfn_layer.html
        http_api_cfn: apigateway.CfnApi = http_api.node.default_child
        http_api_cfn.add_property_override("Body", openapi)
        http_api_cfn.add_property_deletion_override("Name")
        http_api_cfn.add_property_deletion_override("ProtocolType")
        # let it fail on warnings to be sure everything went right
        http_api_cfn.add_property_override("FailOnWarnings", True)

        # construct arn of createad api gateway (to grant permission)
        http_api_arn = (
            f"arn:{self.partition}:execute-api:"
            f"{http_api.env.region}:{http_api.env.account}:"
            f"{http_api.http_api_id}/*/*/*"
        )

        # grant apigateway permission to invoke api lambda function
        api_lambda.add_permission(
            f"Invoke By {http_api.node.id} Permission",
            principal=iam.ServicePrincipal("apigateway.amazonaws.com"),
            action="lambda:InvokeFunction",
            source_arn=http_api_arn,
        )
        
        # output api gateway url
        core.CfnOutput(self, "HttpApiUrl", value=http_api.url)
_

Pythonユーザーは、 OpenApigateway 構築物に興味があるかもしれません。このプロセスをさらに簡単にするために公開しました。 JSONとYAMLをサポートしています。

0
suud