AppSyncのLambda ResolverをGoで書く。

現在卒業制作にてとある共有サービスを作成しています。

今回CloudとしてAWSを採用しどうせ卒業制作だしGraphQL触ってみるかってことでAWS AppSyncに挑戦しています。

今回のGoのソースは
https://github.com/NozomiSugiyama/appsync-lambda-sample
にあげています。

## 注意!!

- AWS 3週間
- GoLang 1週間 今回が始めて

の初心者の記事です。
編集リクエストおまちしております。

<!-- 今回のソースは [github](https://github.com/is09-souzou/AppSync-Resolver-Mapping-Lambda) にあります。 -->

## AWS AppSyncとは
AppSync自体は、GraphQLを使用したBaaSになります。

GraphQLのsubscriptionにも対応しており、リアルタイム更新も簡単にできるみたい。

詳しくは、

- [公式ドキュメント](https://aws.amazon.com/jp/appsync/product-details/)
- [AWS AppSync – 6 つの新機能を加え本番提供開始](https://aws.amazon.com/jp/blogs/news/aws-appsync-production-ready-with-six-new-features/) 

を見てください。

<img width="1013" alt="Screen Shot 2018-06-22 at 17.56.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/bd0ad26a-334b-4cad-1d00-e4f77b19a008.png">

オンラインエディタでGraphQL Schemaを定義していき、それぞれにResolverを割り当てていく形です。

簡単な処理であれば自分でソースを書かなくとも、Tableを用意しAppSyncのData Sourcesに追加後
<img width="1031" alt="Screen Shot 2018-06-22 at 18.02.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/2ea1a31c-b227-69d7-1d9b-a4e6b243e1e3.png">

上のようにAppSyncに用意されたmapping templateを記述して行けば、Lambdaを使わなくてもアプリを作ることができます。
しかし、DynamoDB以外のSourceを使用したり、細かい権限設定、特別な処理などが必要な場合にはResolverにLambdaをAttachし開発していく流れになっていきます。

今回は、
Query: AppSync -> DynamoDB
Mutation: AppSync -> Lambda -> DynamoDB
にて作成していきます。 


## AWS設定
まずAppSyncにて `Create API` を行いSchemaの定義を行います。
<img width="1022" alt="Screen Shot 2018-06-22 at 19.23.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/d6e13264-42f0-aaa0-d633-1a45026f8d77.png">
今回は作成直後最初にコメントアウトされ用意されていたものを使って行きます。　

```schema.graphql
type Mutation {
	# Put a single value of type 'Post'.
	## If an item exists it's updated. If it does not it's created.
	putPost(id: ID!, title: String!): Post
}

type Post {
	id: ID!
	title: String!
}

type Query {
	# Get a single value of type 'Post' by primary key.
	singlePost(id: ID!): Post
}

schema {
	query: Query
	mutation: Mutation
}
```

GraphQLのTypeに基づき Post Tableを作成します。
<img width="1136" alt="Screen Shot 2018-06-22 at 23.40.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/16551503-d29f-4032-f606-ad7a8f09dfd5.png">


Lambdaを作成します。
<img width="1300" alt="Screen Shot 2018-06-22 at 22.26.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/304d048a-d059-2637-3ac9-5eb96731e32e.png">
ロールをTemplateから作成する際は、DynamoDBへの書き込み権限を追加してください。


AppSyncに戻りData SourceにLambdaとPost Tableを追加します。
<img width="1025" alt="Screen Shot 2018-06-22 at 22.47.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/887d5bdc-9801-3d47-6a0f-0308e741476f.png">

singlePost Queryに↑で作成したPostTable Data SourceをAttachします。
デフォルトで request mapping templateとresponse mapping templateが作成されるのでそのまま使います。　

```requestMappingTemplate
{
    "version": "2017-02-28",
    "operation": "GetItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
    }
}
```

```responseMappingTemplate
$util.toJson($ctx.result)
```

putPost MutationにはAppSync Lambda Data SourceをAttachします。
こちらも同様にrequest mapping templateとresponse mapping templateが作成されるのでそのまま使います。　

```requestMappingTemplate
{
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": $util.toJson($context.args)
}
```

```responseMappingTemplate
$util.toJson($context.result)
```


## ソース

```main.go
package main

import (
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/aws/session"
)

type Post struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

func hander(arg Post) (Post, error) {

	input := &dynamodb.PutItemInput{
		Item: map[string]*dynamodb.AttributeValue{
			"id": {
				S: aws.String(arg.ID),
			},
			"title": {
				S: aws.String(arg.Title),
			},
		},
		TableName: aws.String("post"),
	}

	session, err := session.NewSession(
		&aws.Config{Region: aws.String("ap-northeast-1")},
	)

	if err != nil {
		return Post{}, err
	}

	svc := dynamodb.New(session)

	_, err = svc.PutItem(input)

	return arg, nil
}

func main() {
	lambda.Start(hander)
}

```

aws-sdk-goを使用して作成しました。
Lambdaの返り値を忘れずに。

その後

```bash
GOOS=linux GOARCH=amd64 go build -o main
zip handler.zip ./main
```

buildしてzipに圧縮し
<img width="1298" alt="Screen Shot 2018-06-22 at 22.36.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/32a39b8e-45f0-96e7-beab-e45a4cddb6a8.png">
LambdaにUploadします。
このとき ハンドラ を`main`に変更します。


これで完成です！
実際にテストして見ましょう。

## テスト
AppSyncのQueriesタブから実行できます。

### Mutation
<img width="1379" alt="Screen Shot 2018-06-22 at 23.43.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/990fc3bc-ae4c-7dd4-605b-77bbca195ff4.png">
### Query
<img width="1026" alt="Screen Shot 2018-06-22 at 23.45.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/265961/c5e53b24-98a4-bc04-ec11-6748afea8201.png">

データの追加と取得ができています！

## まとめ
AppSyncのData SourceとしてLambdaを使用してみたけど、そんなに難しいことなく簡単に作れたのでよかったです。
ある程度しっかりしたアプリを作るにはLambdaがまだ必須な気がしますが、まだ本番提供開始してからまもないのでこれからの新機能が楽しみです！