前回、Data sourceがDynamoDBである AWS AppSync APIをPythonで呼んでみました。
Pythonで、 AWS AppSyncのquery・mutation・subscriptionを試してみた - メモ的な思考的な
ただ、AWS AppSync のData sourceでは、DynamoDBの他
などもData sourceとして設定できます。
そこで今回は、AWS LambdaをData source にもつ AWS AppSync APIを作成し、Pythonから呼んでみることにしました。
なお、公式ドキュメントにもチュートリアルはありますが、もう少し単純なもので試してみます。
チュートリアル : AWS Lambda リゾルバー - AWS AppSync
また、誤りがありましたらご指摘ください。
目次
環境
Lambdaを作成
AppSync APIを作る前に、Data sourceとなるLambdaを作成します。
AppSync APIから呼ぶLambdaは、
の3つの引数を伴って呼び出されます。
今回は、eventとcontextの値をAppSync APIに戻すようなLambdaを用意します。
Lambdaの設定です。
項目 | 値 |
---|---|
関数名 | AppSyncDatasource |
ランタイム | Node.js 10.x |
アクセス権限 - 実行ロール | 基本的なLambdaアクセス権限で新しいロールを作成 |
実装です。
exports.handler = (event, context, callback) => { // callback関数を使って、レスポンスを返す // 今回は、eventとcontextの値を返してみる callback(null, { "field": event.field, "event": JSON.stringify(event, 3), "context": JSON.stringify(context, 3), }); };
AppSync APIの作成
新規作成
今回は Build from scratch
より作成します。
API nameは、 My AppSync Lambda App
とします。
Data sourceの作成
設定内容は以下の通りです。
項目 | 値 |
---|---|
Data source name | LambdaSource |
Data source type | AWS Lambda function |
Region | 作成したLambdaと同じリージョン |
Function ARN | 作成したLambda (AppSyncDatasource) |
Create or use an existing role | New role |
Schemaの作成
AppSync APIのメニュー Schema
より作成します。
今回はデータ取得を試しますので、Queryだけ用意します。
type Query { ham(req: String!): ResponseData spam(req: String!): ResponseData } type ResponseData { field: String event: String context: String } schema { query: Query }
ポイントは type ResponseData
です。定義した項目
- field
- event
- context
は、いずれもLambdaのcallback関数の第二引数(連想配列)のキーと同じ名称とします。
// 参考:Lambdaの該当箇所 callback(null, { "field": event.field, "event": JSON.stringify(event, 3), "context": JSON.stringify(context, 3), });
また、
- ham
- spam
という2つのQueryを用意し、少しだけ実装を変えてみます。
SchemaとResolverを紐付ける
Schemaを作成しただけではAppSync APIとLambdaは連携しません。
そこで、SchemaとResolverを紐づけし、連携できるようにします。
Schemaメニューの右にある Resolvers から、Queryの ham
の Attach
をクリックします。
Resolverには
- request mapping template
- response mapping template
の2つがあるため、それぞれ設定していきます。
request mapping template
request mapping templateでは、AppSync APIに来たリクエストをどのようにLambdaへ流すかを指定します。
まずは Query ham を設定します。
{ "version" : "2017-02-28", "operation": "Invoke", "payload": { "field": "from_ham", "args": $util.toJson($context.args) } }
ポイントは payload
です。
payloadに指定した連想配列のキーが、Lambdaの引数 event
のプロパティ名となります。
例えば、AppSync APIのpayloadのキー field
の値は、Lambda内では event.field
で取得できます。
// 参考:Lambdaの該当箇所 exports.handler = (event, context, callback) => { callback(null, { "field": event.field, ...
また、 $context.args
は、AppSync API のリクエストパラメータを指します。
一方、Query spamの request mapping template では固定値を設定している項目 field
の値だけを変えてみます。
{ "version" : "2017-02-28", "operation": "Invoke", "payload": { "field": "from_spam", "args": $util.toJson($context.args) } }
response mapping template
こちらは、Lambdaの戻り値を、AppSync APIへどのように渡すかを指定します。
Query ham/spam とも、Lambdaの戻り値をそのままJSONとして返すため、
$util.toJson($context.result)
とします。
これを元にして、AppSync APIのGraphQLで値を取得できます。
以上で、AppSync APIの設定が終わりました。
PythonのGraphQLクライアント作成
前回同様、 graphqlclient
を使って、AppSync APIへとアクセスしてみます。
API_KEY, API_URLは、AppSync APIのSettingsにあるものを設定します。
from graphqlclient import GraphQLClient from secret import API_KEY, API_URL def execute_query_api(gql_client): # ham Queryの実行 ham = """ query { ham(req: "456") { field event context } } """ ham_result = gql_client.execute(ham) print(ham_result) # spam Queryの実行 spam = """ query { spam(req: "789") { field event context } } """ spam_result = gql_client.execute(spam) print(spam_result) if __name__ == '__main__': c = GraphQLClient(API_URL) c.inject_token(API_KEY, 'X-Api-Key') execute_query_api(c)
実行結果
上記のPythonを実行すると以下の結果が得られました*1。
Query: ham の結果
{"data": {"ham":{ "field":"from_ham", "event":"{\"field\":\"from_ham\",\"args\":{\"req\":\"456\"}}", "context":"{\"callbackWaitsForEmptyEventLoop\":true, \"functionVersion\":\"$LATEST\", \"functionName\":\"AppSyncDatasource\", \"memoryLimitInMB\":\"128\", \"logGroupName\":\"/aws/lambda/AppSyncDatasource\", \"logStreamName\":\"2019/07/xx/[$LATEST]xxx\", \"invokedFunctionArn\":\"arn:aws:lambda:region:iam:function:AppSyncDatasource\", \"awsRequestId\":\"xx-xx-xx-xx-xx\"}"}}}
Query: spamの結果
{"data": {"spam":{ "field":"from_spam", "event":"{\"field\":\"from_spam\",\"args\":{\"req\":\"789\"}}", "context":"{\"callbackWaitsForEmptyEventLoop\":true, \"functionVersion\":\"$LATEST\", \"functionName\":\"AppSyncDatasource\", \"memoryLimitInMB\":\"128\", \"logGroupName\":\"/aws/lambda/AppSyncDatasource\", \"logStreamName\":\"2019/07/xx/[$LATEST]xxx\", \"invokedFunctionArn\":\"arn:aws:lambda:region:iam:function:AppSyncDatasource\", \"awsRequestId\":\"xx-xx-xx-xx-xx\"}"}}}
この結果より、
Python -> AWS AppSync API -> AWS Lambda
という経路で、データを取得できているようです。
ソースコード
GitHubに上げました。ディレクトリ lambda_datasource
が今回のソースコードです。
https://github.com/thinkAmi-sandbox/AWS_AppSync_python_client-sample
*1:見やすくするよう改行を入れていますが、実際は一行です