AppSyncを使ってみる

# AppSync

* APIGateway → 複数のAPIエンドポイントを提供
* AppSync → 単一のGraphQLのエンドポイントを提供

## GraphQL

[GraphQL](https://graphql.org/)の何がいいの？

1. 必要なデータだけを取得 
RestfulなAPIではレスポンスの情報は決まっているので、必要ない情報も全て取得せざるを得ない。
→ GraphQLではサーバ側で必要ない情報をフィルタリングして返却する。

2. 一度のリクエストで多くのリソースを取得 
RestfulなAPIでは1つの処理をするのにいくつものURLからAPI経由でデータを取得する必要があるケースが多い。 
→ GraphQLでは1度のリクエストで必要なデータを取得することでパフォーマンス向上を図ることができる。

3. 型を見れば動きがわかる 
RestfulAPIでは仕様書を見ないとパスからはレスポンスがわからなかった。
→ GraphQLではスキーマ定義≒仕様書なので型をみれば何が返るかがわかる。仕様書のメンテコストの削減。

4. version管理しない 
RestfulAPIではパスを変えエンドポイントを増やすことでversionを管理するが、管理が大変。 
→ GraphQLでは呼び出し元で明示的に取得する値を指定するため対応しやすい。`@deprecated`を付すことで削除予定であることを明示できる。

5. データや言語に依存しない 
種々の言語に対応。AppSyncではSDL(Schema Definition Language)で記述する。

## やってみる
### スキーマとリゾルバ
▼ スキーマ定義とそこで定義したノードに対応するリゾルバのコンソール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/f0f2b06d-db08-40aa-677f-033b764cb157.png)
▼ スキーマ定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/86515e9b-1cfd-798a-fe39-da0e6c87cdbf.png)
▼ リゾルバ定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/6975464f-a7c3-9f30-8a18-ba05666aaac1.png)
→ [マッピングテンプレートの文法](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-putitem)

### データソース
= リゾルバの処理する先。どこのデータソースに対してリクエストを投げるか。

### Postmanからコールする
参考) https://learning.postman.com/docs/sending-requests/supported-api-frameworks/graphql/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/d888b4d9-bf2e-6149-44a9-957f8f06103b.png)

## データソースをLambdaとする場合
DynamoDBをデータソースとする場合にはマッピングテンプレートの中で処理を記述していたが、AppSyncから直接アクセスできないRDSやEC2上に独自構築したDBなどをデータソースとする場合にはLambdaを噛ませ、その中に処理を書く必要がある。

### リゾルバ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/39a097b6-b9c0-a53c-dce8-0772dd216d5d.png)
DynamoDBの時と違ってLambdaにリクエストを横流しするだけ。種々のクエリはLambda側で処理を振り分ける必要がある。

### データソース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/03a26a8f-2b0f-b96f-cc95-c3625f804ce4.png)

## リゾルバ
スキーマ定義のすべてのノードに対してリゾルバをアタッチできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/886931a1-7607-def5-6f4e-be672ff3efbe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/a1d0cb01-9c71-bffe-5ff4-b22539670ec6.png)

なぜ値(ノード)に対してもリゾルバがアタッチできるのか？
→ GraphQLがグラフとしての性質を利用していることを考えるとわかる。
→ [この記事](https://qiita.com/tetsuya-zama/items/0f972dced8decd85ad7b)がとてもわかりやすい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/32d7231e-564e-bd1d-75ae-35996bcb9380.png)

この仕組みにより、上記の例では`relatedPost`が呼ばれた時だけリゾルバで再起的に処理されて値が返され、逆に`relatedPost`が呼ばれない時にはこの処理をしなくていいので無駄な演算なくレスポンスを返すことができる。(RestfulAPIではリクエスト側が必要としていないデータだったとしても内部の不要な演算を省いたりできないのでGraphQLのメリットの一つ。)
ただし、ここでもし`getPost`で生成されるPostノードが複数あり、それぞれに対して`relatedPost`を求めるリゾルバを呼ぶとなるとLambdaのコール回数がバカにならないので困る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/438cbe59-9981-c48d-93ff-211f4c8ba853.png)
そこで、リクエストマッピングテンプレートにて`BatchInvoke`を指定することですべてのPostを1度のLambdaで処理することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/003058d6-fa99-7f63-c0ff-4104a8713419.png)

## エラーハンドリング
Lambdaでエラーした場合、リクエストにエラーの内容が含まれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/15b3f0d6-eef9-56d2-736e-70db058c2a4a.png)