GraphQL、AppSyncを使ってDynamoDBにデータを挿入してみた

今回は`GraphQL`と`AppSync`を扱って、`DynamoDB`にデータを挿入する方法を記事にしてみました。

# `Schema`を定義する

以下のように`AppSync`の`Schema`から定義することも可能なのですが、
<img width="955" alt="スクリーンショット 2019-11-02 18.44.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441587/008eb65d-1255-c514-640a-f6ee23e58eaa.png">

私は`Amplify CLI`で作成されるテンプレートである`schema.graphql`のファイルを直接編集することでデータを定義していきたいと思います。尚、`schema.graphql`は`Amplify`用のプロジェクトを準備する`amplify init` コマンドを叩いた際に自動生成されます。この記事以降`Amplify`のCLIコマンドを使いアプリを実装していくため、`Schema`はプロジェクトファイルの方で定義していきます。

## データの設計

ホテルの管理画面アプリを例にデータの設計を考えてみます。必要なデータは


|カラム名|物理名|
|:---:|:---:|
|宿泊部屋のタイプ(シングル、ダブルなど)|type|
|部屋の状況(予約されているか、空室かなど)|status|
|部屋番号|number|
|部屋の清掃状況|houseKeeping|
|宿泊者情報|guestInfo|
|宿泊者代表名|name|
|いつ来たのか|startedAt|
|いつ帰るのか|leavesAt|


ざっとこんな感じですかね。

## 実際にSchemaに定義してみる
`schema.graphql`には以下のように定義しました

```graphql:schema.graphql
type UserType @model {
  id: ID!
  type: String!
  status: String!
  number: String!
  houseKeeping: [String]
  guestInfo: GuestInfo
}
type GuestInfo {
  name: String
  startedAt: String
  leavesAt: String
}
```
`guestInfo` に中身をオブジェクトにし、`name`、`startedAt`、`leavesAt`の3つを持つように設計しました。
続いて`UserType`テーブル(テーブル名を自身で定義したもの)の中身に説明が必要なワード、記号について解説していきます。

### `@model`について
以下公式サイトから引用
> GraphQL Transform 使用して、DynamoDB によってサポートされる API の最上位オブジェクトタイプを定義するディレクティブです。必要なすべての CRUDL (作成、読み取り、更新、削除、および一覧表示) クエリと変化、およびそのような変化の通知を受けるサブスクリプションを生成する

今回の例でいうと、`UserType`テーブルが最上位のオブジェクトタイプになり、`GuestInfo`が第２次のオブジェクトタイプになるため、`UserType`の横に`@model`をつけます。`@model`をつけることにより、最上位のテーブル同士でデータのやり取りができるようになる[`@connection`](https://aws-amplify.github.io/docs/cli-toolchain/graphql#connection)など新たなディレクティブが使用できるようになります。

### `!`について
`!`が意味することは「必ずデータを挿入しなければいけない」です。NOT NULL制約(undefined値、null値は受けつけない)ですね。今回の例で言えば`guestInfo`のデータは挿入しなくてもいいけど、`type`は入れなきゃエラーで怒られるよって定義することになります。必須フィールドには`!`をつけましょう!


## DynamoDBとの連携(create)
`Schema`を定義した後、`amplify push`コマンドを叩き、`App Sync`に`Schema`情報を登録しましょう。
`Schema`が`Appsync`に反映されたのを確認したら、いよいよクエリ言語の`GraphQL`でデータを挿入してみます。

``` graphql:GraphQL
mutation user {
  createUserType(input:{
      status:"occupied"
      number:"101"
      type:"family"
      houseKeeping:["clean"]
      guestInfo: {
        name:"Ichiro Suzuki"
        startedAt:"2017-09-15"
        leavesAt:"2017-09-18"
      }
      
  }) {
    id
    number
    type
    houseKeeping
    guestInfo {
    name
    startedAt
    leavesAt
  }
  }
}
```

```json:結果
{
  "data": {
    "createUserType": {
      "id": "35dba6de-013a-45b9-bc21-165bdaded3ca",
      "number": "101",
      "type": "single",
      "houseKeeping": [
        "clean"
      ],
      "guestInfo": {
        "name": "Ichiro Suzuki",
        "startedAt": "2017-09-15",
        "leavesAt": "2017-09-18"
      }
    }
  }
  ```

<img width="823" alt="スクリーンショット 2019-11-01 22.22.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441587/79993d17-8e43-908e-ced5-3e4406f99403.png">

手順と一緒に解説していきます。
### ①`Type`型の宣言
<img width="336" alt="スクリーンショット 2019-11-01 22.15.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441587/dc86f991-7c85-632d-8503-e99463975d8e.png">

`GraphQL`はリクエストのみの`query`、データを変更する`mutation`、サーバーサイドからのイベントを通知できる`subscription`による3つの`type`型があります。今はデータを挿入したいので`mutation`を宣言します

```graphql:GraphQL
mutation user {
```
ちなみに`user`の変数名は自由に変更できます

### ②クエリ実行
`mutation`つまりデータの変更にはデータを新しく作る`create`、削除する`delete`、更新する`update`の3つがあります。
ここでイチロー選手がホテルに宿泊する新しいデータを作ってみましょう。そのために、`create`+`UserType`(テーブル名)を書いてあげます

```:GraphQL
createUserType(input:{
      status:"occupied"
      number:"101"
      type:"family"
      houseKeeping:["clean"]
      guestInfo: {
        name:"Ichiro Suzuki"
        startedAt:"2017-09-15"
        leavesAt:"2017-09-18"
      }
  ・・・
 ```

### ③返して欲しいデータを書く
```:GraphQL
 {
    id
    number
    type
    houseKeeping
    guestInfo {
    name
    startedAt
    leavesAt
  }
  }
}
```
このようにクエリを実行した後、返して欲しいデータを書きます。極端な話、`id`だけでも大丈夫です。返して欲しくないデータがあれば、通信量などを考慮し、書かない選択も可能です

以上の手順を行うと、このように`DynamoDB`にデータが挿入されます。

<img width="1212" alt="スクリーンショット 2019-11-01 22.54.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441587/b3752928-61c6-2f78-9481-d4e89a0576b8.png">
<img width="1212" alt="スクリーンショット 2019-11-01 22.54.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441587/de2db786-0e32-fbfe-6b78-31214c1c57db.png">


##  DynamoDBとの連携(list)
次にテーブルのデータの一覧を取得したい場合の`query`型から`list`のクエリも実行してみたいと思います

```graphql:GrapQL
query list {
  listUserTypes {
    items {
      number
    }
  }
}
```
```json:結果
{
  "data": {
    "listUserTypes": {
      "items": [
        {
          "number": "103"
        },
        {
          "number": "202"
        },
        {
          "number": "203"
        },
        {
          "number": "403"
        },
        {
          "number": "101"
        },
        {
          "number": "402"
        },
        {
          "number": "201"
        },
        {
          "number": "401"
        },
        {
          "number": "302"
        },
        {
          "number": "303"
        },
        {
          "number": "102"
        },
        {
          "number": "301"
        }
      ]
    }
  }
}
```
`number`データが全て取得できました！

因みに`number`は「数値型」の意味なので、命名としては良くないと言うご指摘を受けました。
`roomNumber`などにするべきでしたね、、、、今後変数名には気をつけます！

次回は`Amplify`の認証機能について記事を書いていこうと思います！