[初心者向け] Lambda 非プロキシ統合で API Gateway API をビルドする をプロキシ統合にして比較してみる

2019.12.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おはようございます、もきゅりんです。

個人的に、今月はAPI Gateway(REST) と仲良くなろう月間でした。

前回はこのようなまとめをしました。

今度こそ (REST) API Gateway と仲良くなるための個人的まとめ

今回のターゲットはプロキシ統合です。

プロキシ統合とは

プロキシ統合には、過去弊社記事にもこのようなものがあります。

API Gateway が「Lambda プロキシ統合」でさらに使いやすくなっててびっくりした話

API Gateway の Lambda プロキシ統合をセットアップする に記載されていることを簡潔にまとめると、Lambdaのプロキシ統合とは以下のようなものだと分かりました。

  • クライアントの API リクエストをLambda 関数に raw リクエストをそのまま渡せること
  • プロキシ統合のLambda 関数は決められた形式で返却する必要があること
  • プロキシリソース {proxy+} とすべてのメソッドに対応する ANYメソッド を併用するとさらに強力であること

うん、なるほど(よく分からん)。

とりあえず便利なものということは伝わります。

ということで、では実際に、シンプルなLambdaの実装で、プロキシ統合と非プロキシ統合(カスタム統合)の両方を対応して比較してみることにしました。

チュートリアル: Lambda 非プロキシ統合で API Gateway API をビルドする

まずは、非プロキシ(カスタム)統合からやっていきます。

元ネタは、チュートリアル: Lambda 非プロキシ統合で API Gateway API をビルドする です。

やることとしては、パラメータを付与してPOSTなりすると、そのパラメータを使って以下のようなレスポンスをしてくれるものです。

{ "greeting": "Good {time}, {name} of {city}.[ Happy {day}!]" }

Lambda関数の作成

公式のチュートリアルだとNode.jsなのですが、Python3.7に書き換えてます。(Node.jsを知らんので)

import json

DAYS = ['Sunday', 'Monday', 'Tuesday',
        'Wednesday', 'Thursday', 'Friday', 'Saturday']
TIMES = ['morning', 'afternoon', 'evening', 'night', 'day']

print('Loading function')


def lambda_handler(event, context):
    name = 'you' if not event['name'] else event['name']
    city = 'World' if not event['city'] else event['city']
    time = 'day' if not event['time'] in TIMES else event['time']
    day = None if not event['day'] in DAYS else event['day']

#   Generate a greeting
    greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '
    if day:
        greeting += 'Happy ' + day + '!'

#   Log the greeting to CloudWatch
    print('Hello: ', greeting)

    dic = {}
    dic["greeting"] = greeting

    return json.dumps(dic)

API Gatewayの設定

APIの作成は、チュートリアル通りなので、引っかかりそうな点以外は省いていきます。

(API Gateway Cors の有効化を選択します。とは書かれていますが、特に有効化しなくても問題なかったです。)

リソースからメソッドが作成できます。

resource-method

メソッドリクエストの設定では、HTTPのリクエストメッセージのどの部分をパラメータとして受け取るかを設定していきます。

method-parameters

モデルとマッピングテンプレートの項で、何だこれは?となりますが、下記を参照して確認していきます。

リクエストおよびレスポンスマッピングのモデルおよびマッピングテンプレートを作成する

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "GetStartedLambdaIntegrationInputModel",
  "type": "object",
  "properties": {
    "callerName": { "type": "string" }
  }
}

上記のモデルの中身については、

"$schema": "http://json-schema.org/draft-04/schema#"は、データモデル JSON schema draft 4を使っている、type は object で、propertiesオブジェクトに callerName を string で設定しますよ、というものですね。

マッピングテンプレートは、Velocity Template Language (VTL) というスクリプトで表されるテンプレートで、ここでは、前段のメソッドリクエストの形式をLambdaにわたす前に変換する役割です。

リクエストされた各パラメータからそれぞれのkeyに値を当てはめ、リクエストボディの中身からcallerName("John")を取得してjsonにする、というものです。

#set($inputRoot = $input.path('$'))
{
  "city": "$input.params('city')",
  "time": "$input.params('time')",
  "day":  "$input.params('day')",
  "name": "$inputRoot.callerName"
}

それでは、下記のパラメータをセットしてテストしてみましょう。

  • メソッド: POST
  • パス: Seattle
  • クエリ文字列: time=morning
  • ヘッダー: day:Wednesday
  • リクエスト本文: { "callerName":"John" }

問題ないようなので、適当なステージ名でデプロイして、curlします。

curl -X POST \
  'https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/Seattle?time=evening' \
  -H 'content-type: application/json' \
  -H 'day: Thursday' \
  -d '{
	"callerName": "John"
}'

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

テスト同様、返ってきました。

なるほどなるほど。これがカスタム統合。

Lambda プロキシ統合で API Gateway API をビルドする

同じ内容を今度はプロキシ統合で対応してみます。

Lambda関数の作成

プロキシ統合では、Lambdaの返却方法と受け取り方が決まっているので、 *1先のPython3.7のコードを修正します。

import json
import ast
DAYS = ['Sunday', 'Monday', 'Tuesday',
        'Wednesday', 'Thursday', 'Friday', 'Saturday']
TIMES = ['morning', 'afternoon', 'evening', 'night', 'day']

print('Loading function')


def lambda_handler(event, context):
    body = event['body']
    body= ast.literal_eval(body)
    name = 'you' if not body['name'] else body['name']
    city = 'World' if not event['pathParameters']['proxy'] else event['pathParameters']['proxy']
    time = 'day' if not event['queryStringParameters']['time'] else event['queryStringParameters']['time']
    day = None if not event['headers']['day'] in DAYS else event['headers']['day']

#   Generate a greeting
    greeting = 'Good ' + time + ', ' + name + ' of ' + city + '. '
    if day:
        greeting += 'Happy ' + day + '!'

#   Log the greeting to CloudWatch
    print('Hello: ', greeting)

    dic = {}
    dic["greeting"] = greeting
    
#   Output Format
    return {
        'statusCode': 200,
        'headers': {
            "x-custom-header": "my custom header value"
        },
        'body': json.dumps(dic),
        'isBase64Encoded': False
    }

API Gatewayの設定

リソースを作成して、プロキシリソースを選択すると、勝手に入力されます。 CORS有効化はいりません。

proxy-resource

保存すると、Lambdaの場合、関数入れるだけの状態です。

select-lambda-function

下記パラメータをセットしてテストします。

  • メソッド: POST
  • パス: LosAngels
  • クエリ文字列: time=evening
  • ヘッダー: day:Friday
  • リクエスト本文: { "name":"Michael" }

問題ないようなので、デプロイして、curlします。

curl -X POST \
  'https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/LosAngels?time=evening' \
  -H 'content-type: application/json' \
  -H 'day: Friday' \
  -d '{
	"name": "Michael"
}'

{"greeting": "Good evening, Michael of LosAngels. Happy Friday!"}%

ほへー! 確かに、手間なく手早くお手軽設定できる、という便利さがわかりました!

でもカスタム統合も個人的には味わい深さがありましたので、もっと味わいたくなりました。

API Gateway とちょっとナカヨクナレタカナ。

以上です。

どなたかのお役に立てば幸いです。

参考:

脚注