前回までのあらすじ
前々回の記事でAPI Gatewayを使ってAPIのモックを作ってみました。
API Gatewayの統合リクエストの統合タイプ:Mockを使えば固定値を返すAPIモックは簡単に作れることが分かったので、今後も業務でちょこちょこ作っていこうと思います。
が、いちいちAWSコンソールから作るのが面倒なので、Slackからサクッと作れるようにしたいと思います。
API Gatewayを作るLambda(Python)の作成
PythonからAWSをコントロールするためにBoto3を使います。
参考にしたBoto3のドキュメント。
Slackでのキーワード
Slackからは以下のキーワードでAPI Gatewayを作ることにします。
api_gateway [API名] [リソース名] [メソッド] [ステータスコード] [レスポンスボディ] [ステージ名]
Slackから受け取った上記のキーワードをLambdaでは以下のように取り出して変数に格納することにします。
# クエリ文字列解析
query = parse_qs(event.get('body') or '')
SETTINGS = query.get('text', [''])[0].split(' ')
API_GATEWAY_NAME = SETTINGS[1]          # API名
PATH_PART = SETTINGS[2]                 # リソース名
HTTP_METHOD = SETTINGS[3]               # メソッド
STATUS_CODE = SETTINGS[4]               # ステータスコード
RESPONSE_TEMPLATES = SETTINGS[5]        # レスポンスボディ
STAGE_NAME = SETTINGS[6]                # ステージ名
API Gatewayの作成
REST_API_ID = agw.create_rest_api(name = API_GATEWAY_NAME)
ルートのリソースIDの取得とリソースの作成
# ルートのリソースIDの取得
PARENT_ID = agw.get_resources(restApiId = REST_API_ID['id'])
# リソースの作成
RESOURCE_ID = agw.create_resource(
    restApiId = REST_API_ID['id'],
    parentId = PARENT_ID['items'][0]['id'],
    pathPart = PATH_PART
    )
メソッドリクエストの作成
agw.put_method(
    restApiId = REST_API_ID['id'],
    resourceId = RESOURCE_ID['id'],
    httpMethod = HTTP_METHOD,
    authorizationType = 'None'
    )
統合リクエストの作成
agw.put_integration(
    restApiId = REST_API_ID['id'],
    resourceId = RESOURCE_ID['id'],
    httpMethod = HTTP_METHOD,
    type = 'MOCK',
    requestTemplates = {'application/json':'{"statusCode":' + STATUS_CODE + '}'}
    )
メソッドレスポンスの作成
agw.put_method_response(
    restApiId = REST_API_ID['id'],
    resourceId = RESOURCE_ID['id'],
    httpMethod = HTTP_METHOD,
    statusCode = STATUS_CODE,
    responseModels = {'application/json': 'Empty'}
    )
統合レスポンスの作成
agw.put_integration_response(
    restApiId = REST_API_ID['id'],
    resourceId = RESOURCE_ID['id'],
    httpMethod = HTTP_METHOD,
    statusCode = STATUS_CODE,
    responseTemplates = {'application/json': RESPONSE_TEMPLATES }
    )
作成したAPIのデプロイ
agw.create_deployment(
    restApiId = REST_API_ID['id'],
    stageName = STAGE_NAME
    )
呼び出しURLをSlackに返す
手を抜いてリージョンはコードに埋め込んでいるので、可変にしたい場合は変数で逃しておいてください。
RESOURCE_NAME = agw.get_resources(restApiId = REST_API_ID['id'])
URL = 'https://' + REST_API_ID['id'] + '.execute-api.ap-northeast-1.amazonaws.com/' + STAGE_NAME + '/' + PATH_PART
return {
    'statusCode': 200,
    'body': json.dumps({
        'text': URL
        })
     }
コードのまとめ
上記のコードをまとめると以下のようになります。
余計なリクエストを受けないようにSlackトークンをチェックしています。
SlackトークンはLambdaの環境変数にセットしそれをos.environ.get('SLACK_TOKEN')で呼び出しています。
Slackのキーワードが不足している時の処理などは入れていないので、必要に応じて追加してください。
import boto3
import json
import os
from urllib.parse import parse_qs
 
agw = boto3.client('apigateway')
token = os.environ.get('SLACK_TOKEN')
 
def lambda_handler(event, context):
     
    # クエリ文字列解析
    query = parse_qs(event.get('body') or '')
     
    # 設定値
    SETTINGS = query.get('text', [''])[0].split(' ')
    API_GATEWAY_NAME = SETTINGS[1]          # API名
    PATH_PART = SETTINGS[2]                 # リソース名
    HTTP_METHOD = SETTINGS[3]               # メソッド
    STATUS_CODE = SETTINGS[4]               # ステータスコード
    RESPONSE_TEMPLATES = SETTINGS[5]        # レスポンスボディ
    STAGE_NAME = SETTINGS[6]                # ステージ名
     
    # slackトークンの確認
    if query.get('token', [''])[0] != token:
        return { 'statusCode': 400 }
     
    # API Gatewayの作成
    REST_API_ID = agw.create_rest_api(name = API_GATEWAY_NAME)
 
    # ルートのリソースIDの取得
    PARENT_ID = agw.get_resources(restApiId = REST_API_ID['id'])
    # リソースの作成
    RESOURCE_ID = agw.create_resource(
        restApiId = REST_API_ID['id'],
        parentId = PARENT_ID['items'][0]['id'],
        pathPart = PATH_PART
        )
     
    # メソッドリクエストの作成
    agw.put_method(
        restApiId = REST_API_ID['id'],
        resourceId = RESOURCE_ID['id'],
        httpMethod = HTTP_METHOD,
        authorizationType = 'None'
        )
     
    # 統合リクエストの作成
    agw.put_integration(
        restApiId = REST_API_ID['id'],
        resourceId = RESOURCE_ID['id'],
        httpMethod = HTTP_METHOD,
        type = 'MOCK',
        requestTemplates = {'application/json':'{"statusCode":' + STATUS_CODE + '}'}
        )
     
    # メソッドレスポンスの作成
    agw.put_method_response(
        restApiId = REST_API_ID['id'],
        resourceId = RESOURCE_ID['id'],
        httpMethod = HTTP_METHOD,
        statusCode = STATUS_CODE,
        responseModels = {'application/json': 'Empty'}
        )
     
    # 統合レスポンスの作成
    agw.put_integration_response(
        restApiId = REST_API_ID['id'],
        resourceId = RESOURCE_ID['id'],
        httpMethod = HTTP_METHOD,
        statusCode = STATUS_CODE,
        responseTemplates = {'application/json': RESPONSE_TEMPLATES }
        )
 
    # 作成したAPIのデプロイ
    agw.create_deployment(
        restApiId = REST_API_ID['id'],
        stageName = STAGE_NAME
        )
         
    # 呼び出しURLをSlackに返す
    RESOURCE_NAME = agw.get_resources(restApiId = REST_API_ID['id'])
    URL = 'https://' + REST_API_ID['id'] + '.execute-api.ap-northeast-1.amazonaws.com/' + STAGE_NAME + '/' + PATH_PART
    return {
        'statusCode': 200,
        'body': json.dumps({
            'text': URL
            })
        }
AWS Gatewayの作成
上記で作ったLambdaを呼び出すAPI Gatewayを以下の設定で作成します。
・ プロトコル:REST
・ メソッド:POST
・ 統合リクエスト
 ・ 統合タイプ:Lambda関数
 ・ Lambdaプロキシ統合の使用:チェックON
 ・ Lambda関数:作成したLambda関数を指定
Slackの発信Webhookの作成
・ Outgoing Webhookで
 ・ チャンネル:botを参加させるSlackチャンネルを指定
 ・ 引き金となる言葉:Lambda関数を起動させるトリガー(今回は「api_gateway」と指定)
 ・ URL:上で作成したAPI Gatewayのステージの呼び出しURL
 ・ トークン:表示されているトークンをコピーして、Lambda関数の環境変数に登録
  ・ キー:SLACK_TOKEN(今回の場合)、値:Slackに表示されているトークン
名前のカスタマイズやアイコンはお好みで。
まとめ
SlackからAPI Gatewayを作れるようになりました。
API Gatewayの削除などまだまだ足りない機能はありますが、上記を参考に追加してみてください。
プチ連載
1回目 AWS API Gatewayでモックを作ってみよう
2回目 AWS API Gateway + Lambda (Python) でモックを作ってみよう
3回目 Slack + Lambda (Python) でAWS API Gatewayモックを作ってみよう(本記事)
We're hiring!
AIチャットボットを開発しています。
ご興味ある方は Wantedlyページ からお気軽にご連絡ください!
参考記事
Boto3 Docs Lambda
Qiita AWS Lambda (Python3) + API Gateway で Slackのbotを作ろう
Qiita [JAWS-UG CLI] API Gateway: #1 RestAPIの作成
Qiita AWS CLIのレスポンス処理は jq 使う前に --query オプションの利用を考えてみよう!
Qiita 【AWS Lambda】API Gatewayを一発で作成するスクリプトを作成してみた(Python版)
AWS CLI Command Reference apigateway