チュートリアル: Lambda 非プロキシ統合を使用して API Gateway REST API をビルドする - Amazon API Gateway

チュートリアル: Lambda 非プロキシ統合を使用して API Gateway REST API をビルドする

このチュートリアルでは、API Gateway コンソールを使用して、クライアントが Lambda 非プロキシ統合 (カスタム統合とも呼ばれます) で Lambda 関数を呼び出すことができる API を構築します。AWS Lambda および Lambda 関数の詳細については、AWS Lambda デベロッパーガイドを参照してください。

分かりやすくするために、API 設定が最小限のシンプルな Lambda 関数で、カスタムの Lambda 統合を使用して API Gateway API を構築する手順について説明します。必要に応じて、いくつかのロジックについて説明します。カスタムの Lambda 統合の詳細な例については、「チュートリアル: 2 つの Calc のサービス統合と 1 つの Lambda 非プロキシ統合を使用して AWS REST API を作成する」を参照してください。

API を作成する前に、次に説明されているように AWS Lambda で Lambda 関数を作成して、Lambda バックエンドをセットアップします。

Lambda 非プロキシ統合用の Lambda 関数の作成

注記

Lambda 関数の作成により、AWS アカウントに料金が請求される場合があります。

このステップでは、「Hello, World!」のような Lambda 関数をカスタムの Lambda 統合用に作成します。このウォークスルーでは、この関数 GetStartedLambdaIntegration が呼び出されます。

この GetStartedLambdaIntegration の Lambda 関数の実装は次のとおりです。

Node.js
'use strict'; var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var times = ['morning', 'afternoon', 'evening', 'night', 'day']; console.log('Loading function'); export const handler = function(event, context, callback) { // Parse the input for the name, city, time and day property values let name = event.name === undefined ? 'you' : event.name; let city = event.city === undefined ? 'World' : event.city; let time = times.indexOf(event.time)<0 ? 'day' : event.time; let day = days.indexOf(event.day)<0 ? null : event.day; // Generate a greeting let greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '; if (day) greeting += 'Happy ' + day + '!'; // Log the greeting to CloudWatch console.log('Hello: ', greeting); // Return a greeting to the caller callback(null, { "greeting": greeting }); };
Python
import json days = {'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'} times = {'morning', 'afternoon', 'evening', 'night', 'day'} def lambda_handler(event, context): print(event) # parse the input for the name, city, time, and day property values try: if event['name']: name = event['name'] except KeyError: name = 'you' try: if event['city']: city = event['city'] except KeyError: city = 'World' try: if event['time'] in times: time = event['time'] else: time = 'day' except KeyError: time = 'day' try: if event['day'] in days: day = event['day'] else: day = '' except KeyError: day = '' # Generate a greeting greeting = 'Good ' + time + ', ' + name + ' of ' + city + '.' + ['', ' Happy '+ day + '!'][day !=''] # Log the greeting to CloudWatch print(greeting) #Return a greeting to the caller return {'greeting': greeting}

カスタムの Lambda 統合の場合、API Gateway は統合リクエストボディとして入力をクライアントから Lambda 関数に渡します。Lambda 関数ハンドラの event オブジェクトが入力です。

Lambda 関数はシンプルです。eventnamecity、および time プロパティの入力オブジェクト (day) を解析します。その後、JSON オブジェクト ({"message":greeting}) として、発信者に挨拶を返します。このメッセージは "Good [morning|afternoon|day], [name|you] in [city|World]. Happy day!" パターンです。これは、Lambda 関数への入力が、以下の JSON オブジェクトのいずれかであることを前提としています。

{ "city": "...", "time": "...", "day": "...", "name" : "..." }

詳細については、「AWS Lambda 開発者ガイド」を参照してください。

さらに、関数は console.log(...) を呼び出して、その実行を Amazon CloudWatch に記録します。これは、関数のデバッグ時に呼び出しをトレースする場合に役立ちます。GetStartedLambdaIntegration 関数で呼び出しを記録できるようにするには、Lambda 関数の適切なポリシーで IAM ロールを設定して CloudWatch ストリームを作成し、そのストリームにログエントリを追加します。Lambda コンソールに従って、必要な IAM ロールとポリシーを作成します。

OpenAPI ファイルから API をインポートする場合など、API Gateway コンソールを使用せずに API をセットアップする場合には、必要に応じて Lambda 関数を呼び出すための API Gateway の呼び出しロールとポリシーを明示的に作成し、設定する必要があります。Lambda 呼び出しと API Gateway API の実行ロールの設定の詳細については、「IAM アクセス許可により API へのアクセスを制御する」を参照してください。

Lambda プロキシ統合用の Lambda 関数、GetStartedLambdaProxyIntegration と比較すると、GetStartedLambdaIntegration Lambda カスタム統合用の Lambda 関数は、API Gateway API 統合リクエストボディからの入力のみを受け取ります。この関数では、JSON オブジェクト、文字列、数値、ブール値、またはバイナリ BLOB の出力を返すことができます。対照的に、Lambda プロキシ統合の Lambda 関数では、リクエストデータから入力を取り込みますが、特定の JSON オブジェクトの出力を返す必要があります。Lambda カスタム 統合の GetStartedLambdaIntegration 関数では、入力として API リクエストパラメータを指定することができますが、クライアントリクエストをバックエンドに転送する前に、API Gateway で、必要な API リクエストパラメータが統合リクエストボディにマッピングされていることを前提としています。そのためには、API デベロッパーは、マッピングテンプレートを作成し、API 作成時に API メソッドで設定する必要があります。

GetStartedLambdaIntegration Lambda 関数の作成します。

GetStartedLambdaIntegration Lambda カスタム統合用の Lambda 関数を作成するには
  1. https://console.aws.amazon.com/lambda/ で、AWS Lambda コンソールを開きます。

  2. 次のいずれかを行ってください。

    • ウェルカムページが表示されたら、[Get Started Now]、[Creae function] の順に選択します。

    • [Lambda > Functions (Lambda > 関数)] リストページが表示されたら、[Create function (関数の作成)] を選択します。

  3. [Author from scratch] を選択します。

  4. [一から作成] ペインで、次の操作を行います。

    1. [Name (名前)] に、Lambda 関数名として GetStartedLambdaIntegration と入力します。

    2. [ランタイム] で、サポートされている最新の Node.js または Python ランタイムのいずれかを選択します。

    3. [Permissions] (許可) で、[Change default execution role] (デフォルトの実行ロールの変更) を展開します。[実行ロール]] ドロップダウンリストで、[AWS ポリシーテンプレートから新しいロールを作成] を選択します。

    4. [Role name] に、ロール名 (GetStartedLambdaIntegrationRole など) を入力します。

    5. [Policy templates] で、[Simple microservice permissions] を選択します。

    6. [関数の作成] を選択します。

  5. [関数の設定] ペインの [関数コード] で、以下の作業を行います。

    1. このセクションの冒頭に表示された Lambda 関数コードをコピーし、インラインコードエディターに貼り付けます。

    2. このセクションのその他のフィールドは、デフォルト設定のままにしておきます。

    3. [デプロイ] を選択します。

  6. 新しく作成した関数をテストするには、[テスト] タブを選択します。

    1. イベント名()で、HelloWorldTest と入力します。

    2. [イベント JSON] では、デフォルトのコードを次のコードに置き換えます。

      { "name": "Jonny", "city": "Seattle", "time": "morning", "day": "Wednesday" }
    3. [テスト] を選択して関数を呼び出します。[実行結果: 成功] セクションが表示されます。[詳細] を展開すると、次の出力が表示されます。

      { "greeting": "Good morning, Jonny of Seattle. Happy Wednesday!" }

      出力は CloudWatch Logs にも書き込まれます。

また、他にも、IAM コンソールを使用して、Lambda 関数と共に作成された IAM ロール (GetStartedLambdaIntegrationRole) を表示することができます。この IAM ロールには、2 つのインラインポリシーがアタッチされています。1 つは、Lambda を実行する上で最も基本的なアクセス許可が指定されているポリシーです。これにより、Lambda 関数が作成されたリージョン内のアカウントのすべての CloudWatch リソース CreateLogGroup に対して CloudWatch を呼び出すことができます。また、このポリシーでは、HelloWorldForLambdaIntegration Lambda 関数で CloudWatch ストリームやログ記録イベントを作成することもできます。

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:region:account-id:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:region:account-id:log-group:/aws/lambda/GetStartedLambdaIntegration:*" ] } ] }

他のポリシードキュメントは、この例で使用されていない他の AWS のサービスの呼び出しに適用されます。この手順はスキップできます。

この IAM ロールには、信頼されたエンティティ (lambda.amazonaws.com) が関連付けられています。信頼関係は次のとおりです。

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

この信頼関係およびインラインポリシーを組み合わせることで、Lambda 関数を使用して、CloudWatch Logs のログイベントに console.log() 関数を呼び出すことができます。

AWS Management Console を使用して Lambda 関数を作成していない場合は、これらの例に従って必要な IAM ロールを作成し、そのロールを手動で関数にアタッチする必要があります。

Lambda 非プロキシ統合を使用して API を作成する

Lambda 関数 (GetStartedLambdaIntegration) を作成してテストしたら、API Gateway API からこの関数を公開できるようになります。例として、汎用的な HTTP メソッドで Lambda 関数を公開します。リクエストボディ、URL パス変数、クエリ文字列、ヘッダーを使用して、クライアントから必要な入力データを受け取ります。API の API Gateway のリクエスト検証を有効にして、必要なデータがすべて適切に定義され、指定されていることを確認します。API Gateway のマッピングテンプレートを設定して、クライアントで指定されたリクエストデータをバックエンドの Lambda 関数で定められた有効な形式に変換します。

Lambda 非プロキシ統合を使用して API を作成するには
  1. API Gateway コンソール (https://console.aws.amazon.com/apigateway) にサインインします。

  2. API Gateway を初めて使用する場合は、サービスの特徴を紹介するページが表示されます。[REST API] で、[構築] を選択します。[Create Example API (サンプル API の作成)] がポップアップ表示されたら、[OK] を選択します。

    API Gateway を使用するのが初めてではない場合、[Create API] (API を作成)を選択します。[REST API] で、[構築] を選択します。

  3. [API 名] に「LambdaNonProxyAPI」と入力します。

  4. (オプション) [説明] に説明を入力します。

  5. [API エンドポイントタイプ][リージョン別] に設定したままにします。

  6. API の作成 を選択します。

API を作成したら、/{city} リソースを作成します。これは、クライアントから入力を受け付けるパス変数を持つリソースの例です。後で、マッピングテンプレートを使用してこのパス変数を Lambda 関数の入力にマッピングします。

リソースを作成するには
  1. [リソースの作成] を選択します。

  2. [プロキシのリソース] はオフのままにします。

  3. [リソースパス]/ のままにします。

  4. [リソース名] に「{city}」と入力します。

  5. [CORS (Cross Origin Resource Sharing)] はオフのままにします。

  6. [リソースの作成] を選択します。

/{city} リソースを作成したら、ANY メソッドを作成します。ANY HTTP 動詞は、実行時にクライアントより送信される有効な HTTP メソッドのクライアントのプレースホルダーです。この例では、ANY メソッドが、Lambda カスタム 統合と Lambda プロキシ統合に使用できることを示します。

ANY メソッドを作成するには
  1. /{city} リソースを選択し、[メソッドを作成] を選択します。

  2. [メソッドタイプ] で、[ANY] を選択します。

  3. [統合タイプ] で、[Lambda 関数] を選択します。

  4. [Lambda プロキシ統合] はオフのままにしておきます。

  5. [Lambda 関数] で、Lambda 関数を作成した AWS リージョンを選択し、関数名を入力します。

  6. 29 秒のデフォルトのタイムアウト値を使用するには、[デフォルトタイムアウト] をオンのままにします。カスタムのタイムアウトを設定するには、[デフォルトタイムアウト] を選択してから、タイムアウト値を 5029000 ミリ秒の間で入力します。

  7. [メソッドの作成] を選択します。

ANY メソッドを作成したら、URL パス変数、クエリ文字列、ヘッダーのリクエストの検証を有効にして、すべての必要なデータが適切に定義され、指定されていることを確認します。この例では、time クエリ文字列パラメータと day ヘッダーを作成します。

リクエストの検証を有効にするには
  1. [メソッドリクエスト] セクションで、[編集] を選択します。

  2. [リクエストの検証] で、[クエリ文字列パラメータおよびヘッダーを検証] を選択します。

  3. [URL クエリ文字列パラメータ] を選択してから、次の操作を行います。

    1. [クエリ文字列の追加] を選択します。

    2. [名前] に time と入力します。

    3. [必須] をオンにします。

    4. [キャッシュ] はオフのままにします。

  4. [HTTP リクエストヘッダー] を選択し、次の操作を行います。

    1. [ヘッダーの追加] を選択します。

    2. [名前] に day と入力します。

    3. [必須] をオンにします。

    4. [キャッシュ] はオフのままにします。

  5. [Save (保存)] を選択します。

リクエストの検証を有効にしたら、バックエンドの Lambda 関数の要求に応じて、受信リクエストを JSON ペイロードに変換するための本文マッピングテンプレートを追加することで、ANY メソッドの統合リクエストを設定します。

統合リクエストを設定するには
  1. [統合リクエスト] セクションで、[編集] を選択します。

  2. [リクエスト本文のパススルー] で、[テンプレートが定義されていない場合 (推奨)] を選択します。

  3. [マッピングテンプレート] を選択します。

  4. [マッピングテンプレートの追加] を選択します。

  5. [コンテンツタイプ] に、「application/json」と入力します。

  6. [テンプレート本文] に、次のコードを入力します。

    #set($inputRoot = $input.path('$')) { "city": "$input.params('city')", "time": "$input.params('time')", "day": "$input.params('day')", "name": "$inputRoot.callerName" }
  7. [Save (保存)] を選択します。

API メソッドの呼び出しをテストする

デプロイ前に API の呼び出しをテストするテスト機関が API Gateway コンソールに表示されます。コンソールのテスト機能を使用して API をテストするには、以下のリクエストを送信します。

POST /Seattle?time=morning day:Wednesday { "callerName": "John" }

このテストリクエストで、ANYPOST{city}Seattle に設定し、Wednesdayday ヘッダー値、"John"callerName 値として割り当てます。

ANY メソッドをテストするには
  1. [テスト] タブを選択します。タブを表示するには、右矢印ボタンを選択する必要がある場合があります。

  2. [メソッドタイプ] では、POST を選択します。

  3. [パス][city] に、「Seattle」と入力します。

  4. [クエリ文字列] に「time=morning」と入力します。

  5. [ヘッダー]] に「day:Wednesday」と入力します。

  6. [リクエスト本文] に、「{ "callerName": "John" }」と入力します。

  7. [Test (テスト)] を選択します。

返されたレスポンスペイロードが次のようになっていることを確認します。

{ "greeting": "Good morning, John of Seattle. Happy Wednesday!" }

ログを表示して、API Gateway によるリクエストおよびレスポンスの処理方法を調べることもできます。

Execution log for request test-request Thu Aug 31 01:07:25 UTC 2017 : Starting execution for request: test-invoke-request Thu Aug 31 01:07:25 UTC 2017 : HTTP Method: POST, Resource Path: /Seattle Thu Aug 31 01:07:25 UTC 2017 : Method request path: {city=Seattle} Thu Aug 31 01:07:25 UTC 2017 : Method request query string: {time=morning} Thu Aug 31 01:07:25 UTC 2017 : Method request headers: {day=Wednesday} Thu Aug 31 01:07:25 UTC 2017 : Method request body before transformations: { "callerName": "John" } Thu Aug 31 01:07:25 UTC 2017 : Request validation succeeded for content type application/json Thu Aug 31 01:07:25 UTC 2017 : Endpoint request URI: https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Endpoint request headers: {x-amzn-lambda-integration-tag=test-request, Authorization=****************************************************************************************************************************************************************************************************************************************************************************************************************************************338c72, X-Amz-Date=20170831T010725Z, x-amzn-apigateway-api-id=beags1mnid, X-Amz-Source-Arn=arn:aws:execute-api:us-west-2:123456789012:beags1mnid/null/POST/{city}, Accept=application/json, User-Agent=AmazonAPIGateway_beags1mnid, X-Amz-Security-Token=FQoDYXdzELL//////////wEaDMHGzEdEOT/VvGhabiK3AzgKrJw+3zLqJZG4PhOq12K6W21+QotY2rrZyOzqhLoiuRg3CAYNQ2eqgL5D54+63ey9bIdtwHGoyBdq8ecWxJK/YUnT2Rau0L9HCG5p7FC05h3IvwlFfvcidQNXeYvsKJTLXI05/yEnY3ttIAnpNYLOezD9Es8rBfyruHfJfOqextKlsC8DymCcqlGkig8qLKcZ0hWJWVwiPJiFgL7laabXs++ZhCa4hdZo4iqlG729DE4gaV1mJVdoAagIUwLMo+y4NxFDu0r7I0/EO5nYcCrppGVVBYiGk7H4T6sXuhTkbNNqVmXtV3ch5bOlh7 [TRUNCATED] Thu Aug 31 01:07:25 UTC 2017 : Endpoint request body after transformations: { "city": "Seattle", "time": "morning", "day": "Wednesday", "name" : "John" } Thu Aug 31 01:07:25 UTC 2017 : Sending request to https://lambda.us-west-2.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:GetStartedLambdaIntegration/invocations Thu Aug 31 01:07:25 UTC 2017 : Received response. Integration latency: 328 ms Thu Aug 31 01:07:25 UTC 2017 : Endpoint response body before transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=c0475a28-8de8-11e7-8d3f-4183da788f0f, Connection=keep-alive, Content-Length=62, Date=Thu, 31 Aug 2017 01:07:25 GMT, X-Amzn-Trace-Id=root=1-59a7614d-373151b01b0713127e646635;sampled=0, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Method response body after transformations: {"greeting":"Good morning, John of Seattle. Happy Wednesday!"} Thu Aug 31 01:07:25 UTC 2017 : Method response headers: {X-Amzn-Trace-Id=sampled=0;root=1-59a7614d-373151b01b0713127e646635, Content-Type=application/json} Thu Aug 31 01:07:25 UTC 2017 : Successfully completed execution Thu Aug 31 01:07:25 UTC 2017 : Method completed with status: 200

このログには、マッピング前の受信リクエスト、およびマッピング後の統合リクエストが示されます。テストに失敗した場合、このログは、元の出力が正しいかどうか、またはマッピングテンプレートが正しいかどうかを評価する上で役立ちます。

API をデプロイする

テスト呼び出しはシミュレーションのため、制限があります。たとえば、API で実施される任意の認証メカニズムはバイパスされます。リアルタイムで API の実行をテストするには、最初に API をデプロイする必要があります。API をデプロイするには、ステージを作成し、その時点の API のスナップショットを作成します。また、ステージ名では、API のデフォルトのホスト名の後にベースパスが定義されます。API のルートリソースはステージ名の後に追加されます。API を変更する場合は、変更が適用される前に既存または新しいステージに再デプロイする必要があります。

API をステージにデプロイするには
  1. [API のデプロイ] を選択します。

  2. [ステージ][新規ステージ] を選択します。

  3. [Stage name (ステージ名)] に test と入力します。

    注記

    入力は UTF-8 でエンコードされた (ローカライズされていない) テキストである必要があります。

  4. (オプション) [説明] に説明を入力します。

  5. デプロイを選択します。

[ステージの詳細] で、コピーアイコンを選択して API の呼び出し URL をコピーします。API のベース URL の一般的なパターンは、https://api-id.region.amazonaws.com/stageName です。たとえば、beags1mnid リージョンで作成され、us-west-2 ステージにデプロイされた API (test) の URL は、「https://beags1mnid.execute-api.us-west-2.amazonaws.com/test」です。

デプロイステージで API をテストする

デプロイされた API をテストするには、いくつかの方法があります。URL パス変数またはクエリ文字列パラメータのみを使用する GET リクエストの場合は、ブラウザに API のリソース URL を入力します。それ以外のメソッドの場合は、POSTMANcURL などのより高度な REST API テストユーティリティを使用する必要があります。

cURL を使用して API をテストするには
  1. インターネットに接続されているローカルコンピュータでターミナルウィンドウを開きます。

  2. POST /Seattle?time=evening をテストするには

    以下の cURL コマンドをコピーして、ターミナルウィンドウに貼り付けます。

    curl -v -X POST \ 'https://beags1mnid.execute-api.us-west-2.amazonaws.com/test/Seattle?time=evening' \ -H 'content-type: application/json' \ -H 'day: Thursday' \ -H 'x-amz-docs-region: us-west-2' \ -d '{ "callerName": "John" }'

    次のペイロードで成功を示すレスポンスが返ります。

    {"greeting":"Good evening, John of Seattle. Happy Thursday!"}

    このメソッドリクエストで POST から PUT に変更した場合も同じレスポンスを受け取ります。

クリーンアップ

このチュートリアルで作成した Lambda 関数が不要になった場合は、削除できます。また、付随する IAM リソースも削除できます。

警告

このシリーズの他のチュートリアルを行う予定の場合は、Lambda 実行ロールまたは Lambda 呼び出しロールを削除しないでください。API が依存する Lambda 関数を削除すると、API は機能しなくなります。Lambda 関数の削除は元に戻すことができません。再度 Lambda 関数を使用するには、関数を再度作成する必要があります。

Lambda 関数が依存する IAM リソースを削除すると、Lambda 関数は機能しなくなります。また、同関数に依存する API は機能しなくなります。IAM リソースの削除は元に戻すことができません。再度 IAM リソースを使用するには、リソースを再度作成する必要があります。

Lambda 関数を削除するには
  1. AWS Management Console にサインインして AWS Lambda コンソール (https://console.aws.amazon.com/lambda/) を開きます。

  2. 関数の一覧から [GetHelloWorld] を選択し、[Actions (アクション)]、[Delete function (関数の削除)] の順に選択します。プロンプトが表示されたら、再度 [削除] を選択します。

  3. 関数の一覧から [GetHelloWithName] を選択し、[Actions (アクション)]、[Delete function (関数の削除)] の順に選択します。プロンプトが表示されたら、再度 [削除] を選択します。

関連付けられた IAM リソースを削除する
  1. IAM コンソール (https://console.aws.amazon.com/iam/) を開きます。

  2. [詳細] から [ロール] を選択します。

  3. ロールのリストから、[ApigateWayLambdaExecRole] を選択し、[Role Actions (ロールアクション)] を選択して、[Delete Role (ロールの削除)] を選択します。プロンプトが表示されたら、[Yes, Delete (はい、削除します)] を選択します。

  4. [詳細] から、[ポリシー] を選択します。

  5. ポリシーのリストから、[ApigateWayLambdaExecPolicy] を選択し、[Policy Actions (ポリシーアクション)] を選択して、[Delete (削除)] を選択します。プロンプトが表示されたら、[削除] を選択します。