amplify+AppSyncの開発でRDSを使いたかった話

AppSyncのデータソースにRDSを指定できるので
amplifyでDynamoDBの代わりに使えるのではないか？
という期待から色々調べた結果、期待通りには出来なかった話。

結論から言うと、以下の通り。

- RDSに自動的にテーブルはできない
- RDSの既存テーブルをモデルとしてGraphqlで利用することはできる
- amplifyで作成したモデルはDynamoDBにテーブルが生成される

## 筆者のスキルレベル
AWS自体触り始めて半年。
amplify+AppSync初めて触った。

理解が割とあやふやなので、間違った事を書いている可能性があります。
よろしくお願いします。

## amplify api add-graphql-datasource

このコマンドでデータソースをRDSにできるんじゃね？
って思ったので調査開始。

## とりあえず叩く

```
# amplify api add-graphql-datasource
Using datasource: Aurora Serverless, provided by: awscloudformation
You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.
```

APIを作っていない場合怒られた。
作ってから再挑戦。

```
# amplify api add-graphql-datasource
Using datasource: Aurora Serverless, provided by: awscloudformation
? Provide the region in which your cluster is located:
? us-east-1
  us-east-2
  us-west-2
  ap-northeast-1
  eu-west-1
```

AppSyncで対応しているRDSはAurora Serverlessしかないため、それがある場所を指定する。
また、接続に使用する認証はSecretで先に定義しておく必要がある。

```
# amplify api add-graphql-datasource
Using datasource: Aurora Serverless, provided by: awscloudformation
? Provide the region in which your cluster is located: ap-northeast-1
? Select the Aurora Serverless cluster that will be used as the data source for your API: sil-database-1
? Select the secret used to access your Aurora Serverless cluster: silsecret
? Fetched Aurora Serverless cluster.
No properly configured databases found.
```

データベースが作成されていないと怒られる。
なのでデータベースを作成

```
# aws rds-data execute-statement --resource-arn "arn:aws:rds:ap-northeast-1:1234567890xx:cluster:sil-database-1" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:ap-northeast-1:1234567890xx:secret:silsecret-AaBbCc"  \
--region ap-northeast-1 --sql "create DATABASE TESTDB"
{
    "generatedFields": [],
    "numberOfRecordsUpdated": 1
}
```

作成したので再挑戦。

```
# amplify api add-graphql-datasource
Using datasource: Aurora Serverless, provided by: awscloudformation
? Provide the region in which your cluster is located: ap-northeast-1
? Select the Aurora Serverless cluster that will be used as the data source for your API: sil-database-1
? Select the secret used to access your Aurora Serverless cluster: silsecret
? Fetched Aurora Serverless cluster.
? Select the database to use as the datasource: TESTDB
Successfully added the Aurora Serverless datasource locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud


The following types do not have '@auth' enabled. Consider using @auth with @model
         - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth

(node:571) UnhandledPromiseRejectionWarning: Error: Type Query must define one or more fields.

Type Mutation must define one or more fields.

Type Subscription must define one or more fields.
    at assertValidSchema (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql/type/validate.js:71:11)
    at Object.validate (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql/validation/validate.js:54:35)
    at Object.exports.validateModelSchema (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql-transformer-core/src/validation.ts:143:10)
    at GraphQLTransform.transform (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql-transformer-core/src/GraphQLTransform.ts:240:20)
    at _buildProject (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql-transformer-core/src/util/amplifyUtils.ts:63:35)
    at ensureMissingStackMappings (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql-transformer-core/src/util/amplifyUtils.ts:137:23)
    at Object.buildProject (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/graphql-transformer-core/src/util/amplifyUtils.ts:30:3)
    at transformGraphQLSchema (/usr/local/lib/node_modules/@aws-amplify/cli/node_modules/amplify-provider-awscloudformation/lib/transform-graphql-schema.js:451:29)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:571) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:571) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
```

データベースを作成しただけではだめだった。
ローカルで定義したモデルがないよ、とかそもそもフィールドの定義が変だよとか言われてる？

# この辺でやっとdocumentを見つける

私は説明書を読まないタイプなので、最初に読めばよかったとかよく後悔します。
https://docs.amplify.aws/cli/graphql-transformer/relational

データソースとして利用できるテーブルを作っておけばいけるらしいのでテーブルを作る。

```
# aws rds-data execute-statement --resource-arn "arn:aws:rds:ap-northeast-1:1234567890xx:cluster:sil-database-1" \
 --schema "mysql"  --secret-arn "arn:aws:secretsmanager:ap-northeast-1:1234567890xx:secret:silsecret-AaBbCc" \
 --region ap-northeast-1 \
 --sql "CREATE TABLE Customers ( id int(11) NOT NULL PRIMARY KEY,  name varchar(50) NOT NULL,  phone varchar(50) NOT NULL,  email varchar(50) NOT NULL)" --database "TESTDB"
{
    "generatedFields": [],
    "numberOfRecordsUpdated": 0
}

# aws rds-data execute-statement --resource-arn "arn:aws:rds:ap-northeast-1:1234567890xx:cluster:sil-database-1" \
 --schema "mysql"  --secret-arn "arn:aws:secretsmanager:ap-northeast-1:1234567890xx:secret:silsecret-AaBbCc" \
 --region ap-northeast-1 \
 --sql "CREATE TABLE Orders (  id int(11) NOT NULL PRIMARY KEY,  customerId int(11) NOT NULL,  orderDate datetime DEFAULT CURRENT_TIMESTAMP,  KEY \`customerId\` (\`customerId\`),  CONSTRAINT \`customer_orders_ibfk_1\` FOREIGN KEY (\`customerId\`) REFERENCES \`Customers\` (\`id\`))" --database "TESTDB"
{
    "generatedFields": [],
    "numberOfRecordsUpdated": 0
}
```

テーブルを作ったので再度

```
# amplify api add-graphql-datasource
Using datasource: Aurora Serverless, provided by: awscloudformation
? Provide the region in which your cluster is located: ap-northeast-1
? Select the Aurora Serverless cluster that will be used as the data source for your API: sil-database-1
? Select the secret used to access your Aurora Serverless cluster: silsecret
? Fetched Aurora Serverless cluster.
? Select the database to use as the datasource: TESTDB
Successfully added the Aurora Serverless datasource locally

Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud


The following types do not have '@auth' enabled. Consider using @auth with @model
         - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth


GraphQL schema compiled successfully.

Edit your schema at /root/boardapp/amplify/backend/api/boardapp/schema.graphql or place .graphql files in a directory at /root/boardapp/amplify/backend/api/boardapp/schema
```

なんとか正常終了しました。

## 未定義モデルはDynamoDBのテーブルが作られる
amplify pushしてみたところ、データソースが二つ登録されました。
追加したTESTDBと、メッセージで色々言われてたTodoのテーブル。
TodoはTESTDBになかったため、push時にDynamoDBに自動生成されたようです。
![boadapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367481/8115346c-22ff-8a90-12f9-e125830516c2.png)

というわけで、当初やりたかった「DynamoDBではなくRDSをデータソースとして利用する」
というのはamplifyではちょっと難しいらしいことがわかりました。
できなくはないですが、RDSのテーブルとamplifyソースを別々に管理する必要がありそうです。

何か間違った事を書いてしまっていたら、ご指摘願います。

## 追記

prismaを使うとRDSが使えるが、amplifyとは連携できるわけではない。

## 参考

[チュートリアル: Aurora Serverless - AWS AppSync](https://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/tutorial-rds-resolvers.html)
[API (GraphQL) - Relational Databases - Amplify Docs](https://docs.amplify.aws/cli/graphql-transformer/relational)
[Aurora Serverless の Data API の使用 - Amazon Aurora](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/data-api.html)
[AWS AppSync + RDS を試してみた - Qiita](https://qiita.com/tasuwo/items/984e6f594cde94e4224e)
[【爆速】React+Amplify+AppSyncでリアルタイム掲示板アプリを15分で作り上げる　〜これが最高のDeveloper Experienceだ〜 - Qiita](https://qiita.com/G-awa/items/a5b2cc7017b1eceeb002)