AppSyncでLambdaを呼び出す

# AppSyncでLambdaを呼び出す

## はじめに
先日「[API Gatewayでリクエストして、Lambdaで処理させて、AppSyncで受け取る](https://qiita.com/w2or3w/items/227465969ecbbef21787#lambda%E3%81%AE%E4%BD%9C%E6%88%90)」という記事を書きました。この記事のあとがきにも書いたのですが、フロントエンドからLambdaを実行させるために何の迷いもなくAPI Gatewayを利用していたのですが、どうやらAppSyncでも出来そうだぞということで。

データソースにDynamoDBを指定しているAppSyncへ、LambdaをデータソースとするIFを追加します。

## スキーマへIFの追加
AppSyncのスキーマに、モザイク処理を実行するためのIFを追加します。
AWSコンソール > AppSync > 目的のAPI > スキーマ
MutationへprocessApplyMosaicという関数、そして入出力用のデータ型を定義します。
入出力用のデータ型はAPI Gatewayの時と同じ仕様とし、また、認証タイプはCognitoとします。

```graphql
 :
input ProcessApplyMosaicInput {
	guid: String!
	orgKey: String!
	pointsList: [String]
}

type ProcessApplyMosaicResult @aws_cognito_user_pools {
	statusCode: Int!
	body: String
}

type Mutation {
	processApplyMosaic(input: ProcessApplyMosaicInput!): ProcessApplyMosaicResult
		@aws_cognito_user_pools
	createSampleAppsyncTable(input: CreateSampleAppsyncTableInput!): SampleAppsyncTable
		@aws_iam
 :
```
スキーマを保存ボタンを押下してください。


## リゾルバーの追加
スキーマを編集して保存すると、スキーマの右側にあるResolversというところに追加したprocessApplyMosaicが表示されるようになります。Resolverはまだ未割り当てなので「アタッチ」ボタンを押下して割り当てることになります。
![Screenshot 2020-03-21 at 00.01.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/e8e8b731-7953-854d-9f0c-c0d65555ac6f.png)
が、一時中断です。その前にやることがあります。

### Lambdaの作成
スキーマのMutationに追加したprocessApplyMosaicのリゾルバーを割り当てるためのLambdaを作成します。

AWSコンソール > Lambda > 関数の作成 > 一から作成
名前は「apply_mosaic_from_appsync」、ラインタイムは「Python 3.6」として作成します。

作成したLambdaのIAMロールに必要な権限を当てておきます。
AWSコンソール > IAM > ロール > Lambdaとセットで作成されたロール(apply_mosaic_from_appsync-role-xxxxxxxx)
S3とAppSyncへのアクセスが必要ですので、以下のような内容でインラインポリシーを追加します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws:s3:::sample-vue-project-bucket-work/*",
                "arn:aws:appsync:ap-northeast-1:888888888888:apis/xxxxxxxxxxxxxxxxxxxxxxxxxx/*"
            ],
            "Effect": "Allow"
        }
    ]
}
```

作成したLambdaに [この記事](https://qiita.com/w2or3w/items/227465969ecbbef21787#lambda%E3%81%AE%E4%BD%9C%E6%88%90) で作成したPythonコードをインポートするわけですが、インプットパラメータを受け取るところの実装を少しだけ変更します。

```py
 :
def lambda_handler(event, context):
    try:
        # guid = event["guid"]
        # orgKey = event["orgKey"]
        # pointsList = event["pointsList"]
        # AppSyncから渡される引数はinputタグの中に入れてるので↓のように変更する。
        guid = event["input"]["guid"]
        orgKey = event["input"]["orgKey"]
        pointsList = event["input"]["pointsList"]
 :
```

### データソースの作成
AWSコンソール > AppSync > 目的のAPI > データソース
データソースの作成ボタンを押下し、先ほど作成したLambdaを選択して作成します。
![Screenshot 2020-03-19 at 00.03.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/6ebbb937-cba0-e9f6-6d59-46bdb0c4b0aa.png)

### リゾルバーへLambdaのアタッチ
それでは中断した作業に戻ります。
AppSyncのスキーマの右側にあるResolversというところに追加したprocessApplyMosaicが表示されるようになり、そこに表示されている「アタッチ」ボタンを押下します。
データソース名のコンボボックスから先ほど作成したデータソースを選択して、「リゾルバーを保存」ボタンを押下します。リクエスト/レスポンス マッピングテンプレートは特に編集しません。![Screenshot 2020-03-19 at 00.06.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/874b9283-7c27-2e28-4d2f-f334c8b5f338.png)

これでAPI側の準備は整いました。

## フロントエンドから呼び出し
それではフロントエンドから呼び出してみましょう。
VueのWebアプリにてAPI Gatewayで呼び出していたところをAppSyncに置き換えることになります。

```src/graphql/mutations.js
export const processApplyMosaic = `
    mutation processApplyMosaic($input: ProcessApplyMosaicInput!) {
        processApplyMosaic(input: $input) {
            statusCode
            body
        }
    }
`;
```

```src/components/List.vue
 : 
<script>
import { Auth, API, graphqlOperation, Storage } from 'aws-amplify';
import { listSampleAppsyncTables } from "../graphql/queries";
import { onCreateSampleAppsyncTable } from "../graphql/subscriptions";
import { processApplyMosaic } from "../graphql/mutations";
 :
    async processMosaic() {
       :       
      /* API Gatewayの時のコード
      const currSession = await Auth.currentSession();
      config.headers["Authorization"] = currSession.getIdToken().getJwtToken();
      axios
      .post(apiUrl, {guid: this.myGuid, orgKey: orgKey, pointsList: pointsList}, config)
      .then(response => {
          let result = response.data
          console.log(result)
      }).catch(error => console.log(error))*/

      let apiResult = await API.graphql(graphqlOperation(processApplyMosaic, 
        {input : {guid: this.myGuid, orgKey: orgKey, pointsList: pointsList}})
      ).catch(error => {
        console.error(error);
      });
    }, 
 :
```
コード的にも、Amplifyで統一できてスッキリしましたね。


## あとがき
AppSyncとAPI Gateway、両方使うことで得られるメリットはアーキテクチャ図のアイコンが増えて華やかになることくらいでしょうか。
というのは流石に冗談が過ぎますね。

目的を実現するための手段は多岐にわたりますが、より多くの選択肢の中から適切に取捨選択できるようになりたいものです。