AWS AppSyncのHTTPデータソース(+JSリゾルバー)で、他AWSサービスと直接連携する
はじめに
AWS AppSyncと他のAWSサービスと連携したいとき、Lambdaを間に挟んでAWS SDKを使ってやり取りするのが普通じゃないかなと思います。(DynamoDBのように直接呼び出す仕組みが用意されているサービスは除く)
しかし、今回はLambdaを使わずにAppSyncからAWSのAPIを呼び出すことで他のAWSサービスを直接連携したいと思います。
すなわち、JSリゾルバーのドキュメントにさらっと書いてあるこの機能を実装します。
(公式の日本語訳ページは意味不明だったのでDeepLで翻訳しました)
この記事やることを、もう少し具体的に
技術的な繋がりがほとんど無いですが、一応前回記事の続きになります。
リソースをなるべく増やしたくないので、Lambdaは挟まずにAppSyncからIoT Eventsを直接呼び出したいと思います。
この記事はAppSyncからIoT Eventsの連携をベースに説明しますが、同じ方法で他AWSサービスとも直接連携が可能です。
実際に構築するための主な参考ドキュメント
実際に構築する
IoT Eventsのディテクターの一覧を取得するAPIをAppSyncで作ります。
とりあえず、適当にAppSyncのリソースを作る
Webのコンソールからでよいので、適当にAppSyncを作ります。
データソースはこの後CLIで作るので、コンソールからは作らないでください。
IoT EventsのAPIを実行するHTTPデータソースを作る
そもそもAWSに対する操作は基本的にAPIを呼び出して実施することが出来ます。
コンソールからの操作もCLIからの操作もSDKからの操作も、裏では全てAPIを呼び出しています。ですので、適切にAPIさえ呼び出せればLambdaとかを使わなくてもAWSリソースの操作は可能なわけです。
つまりAppSyncからAPIが呼べれば良いわけですが、AppSyncにはAPIを呼び出せるデータソースがあります。それがHTTPデータソースです。
AWSのAPI仕様を確認する
AWSのドキュメントを確認すると、ListDetectors APIを呼び出すことで、今回の目的が達成できる事がわかります。
あとは定義どおりに呼び出せばよいわけですが、普通にAPIを呼ぶと認可エラーになってしまいます。
認可を通す為の設定が必要になります。
ロールの作成
今回は前述の通りAPIによりIoT Eventsと連携為にHTTPリゾルバーを使います。
HTTPリゾルバーに適切な権限を付けるために、まずは、IAMでロールを作ります。
IAMロールには、以下のポリシーをアタッチしておきます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iotevents:ListDetectors",
"iotevents:DescribeDetector"
],
"Resource": "*"
}
]
}
ListDetectors
が必要なので、それを許可しています。
将来的にディテクターの詳細も確認したいので、DescribeDetector
も付けておきました。
HTTPデータソースの定義用のjsonを作る
正直良くわかってないのですが、定義用のjsonが必要なので作ります。
AWSのAPIの認可を突破するにはSigV4署名というものが必要なのですが、その署名の為の情報を入れる必要があります。
{
"endpoint": "https://data.iotevents.ap-northeast-1.amazonaws.com",
"authorizationConfig": {
"authorizationType": "AWS_IAM",
"awsIamConfig": {
"signingRegion": "ap-northeast-1",
"signingServiceName": "ioteventsdata"
}
}
}
signingServiceName
の値が分からなくて6回くらい作り直しました。(ioteventsでもdata.ioteventsでも無くてioteventsdata
...分からんよ)
ServiceNameの一覧ってどこかで確認できたりするのでしょうか?
cliからHTTPデータソースを作る
jsonが出来たら、cliからHTTPデータソースを作ります。(webの画面からだとroleやjsonの指定ができないので、cliから作ってください)
aws appsync create-data-source --api-id {appsyncのid} --name {データソース名} --type HTTP --http-config file://iot.json --service-role-arn {さっき作ったロールのarn}
できました。
webの画面上で見るとただのhttpデータソースに見えますが、裏で認可の設定とかが入っているので、AWSのセキュリティを突破してIoT Eventsと連携することができます。
スキーマを作る
スキーマを作ります。
type Task {
id: ID!
title: String
done: Boolean
}
type Query {
getTaskList: [Task]
}
schema {
query: Query
}
パイプラインリゾルバーを作る
画面の右側からgetTaskListを探し「アタッチ」を押下すると、パイプラインリゾルバーを作ることが出来ます。
リゾルバーコードはデフォルトのままでOKです。
関数を追加して、そちらに必要なコードを書いていきます。
関数(JSリゾルバー)を書く
関数を追加したら、まず、データソースに先程cliで作ったHTTPデータソースを選択します。
その後、関数コードを書きます。以前はAppSyncのリゾルバーはVLCというイマイチマイナーな言語で書く必要があり敷居が高かったですが、今では関数を使うことでJavaScriptでも書くことが出来ます。
ドキュメントを読むとリソースのSyntaxは、
GET /detectors/detectorModelName?maxResults=maxResults&nextToken=nextToken&stateName=stateName HTTP/1.1
なので、リソースパスを/detectors/{ディテクター名}
にします。queryパラメータは必要に応じて指定すると良いですが、全て任意なので今回は指定しませんでした。
import { util } from '@aws-appsync/utils';
export function request(ctx) {
return {
version: "2018-05-29",
method: "GET",
resourcePath: "/detectors/ibaraki-test-iot-events",
params: {
headers: {
"Content-Type": "application/json"
},
query: {},
body: JSON.stringify({})
}
}
}
export function response(ctx) {
const { error, result, stash } = ctx;
if (result.statusCode === 200) {
const body = JSON.parse(result.body);
return body.detectorSummaries.map((d) => {
return {
id : d.keyValue,
done : (d.state.stateName == 'done')
};
});
}else{
util.appendError(result.body, result.statusCode);
}
}
パイプラインリゾルバーに関数を追加する
関数を保存したら、パイプラインリゾルバーに設定するのを忘れないようにしましょう。
私は、セットするのを忘れて何も動かず、無駄に30分くらいエラーと戦っていました。
試す
webのコンソールのクエリから、試せるので試します。
ミスってなければ、無事にリストが取得できます。
まとめ
以下の手順でAppSyncと好きなAWSサービスを連携することが出来ます。
- 連携先のAWSサービスのAPI仕様を調べる
- 連携先のAWSサービスの実行を許可するRoleを作る
- HTTPデータソース定義用のjsonを作る
- cliからHTTPデータソースを作る
- パイプラインリゾルバーを作る
- 関数(JavaScriptリゾルバー)を作って、HTTPデータソースを実行するコードを書く
- パイプラインリゾルバーに関数を設定する
今後
今回JSリゾルバーを書いてみて、コンソールからだとJavaScriptが書きにくいと感じました。あとJSでなくてTSで書きたいです。CDKとかを使っていい感じに開発したいところですが、それは次の機会ということで、この記事は以上です。
↓
書きました。CDK+TSでリゾルバーを書く。
NCDC株式会社( ncdc.co.jp/ )のエンジニアチームです。 募集中のエンジニアのポジションや、採用している技術スタックの紹介などはこちら( github.com/ncdcdev/recruitment )をご覧ください! ※エンジニア以外も記事を投稿することがあります
Discussion