Amplify apiで簡単バックエンド構築

今回は、Amplify-CLIを利用したGraphQLのバックエンドAPI構築を紹介します。
手順は[公式](https://aws-amplify.github.io/docs/js/api)を参考に。

# GraphQL/AWS AppSync
GraphQLはFacebookとコミュニティにより開発されたクエリ言語です。典型的なRESTでの大きく以下の３つの問題点を解消するために開発されました。
[GraphQL公式を](https://graphql.org/)見ると他にもメリットが記載されているようですが。

1. 過剰なデータ取得（クライアントにとって必要がないデータでも返却され不必要なリソース消費が起こる）
2. 複数URLへのアクセス（単一の動作の実現でも複数エンドポイントへのアクセスが必要）
3. フロントとバックエンドとの仕様不整合（仕様書などで規約を記載しても仕様変更に更新が追いつかない不整合がたびたび起こる）

AppSyncはそのGraphQLを使用したAWSのマネージド・サービスです。
今回は、apmlifyを利用したAppSyncのAPI構築方法をご紹介します。
# 事前準備
## amplify cliのインストール

```
npm install -g @aws-amplify/cli
amplify configure
```
## amplifyの初期設定

```
amplify init
```
amplify-cliがインタラクティブに設定情報を聞いてくるので、回答します。
[過去記事](https://qiita.com/makishy/items/499961fa64aefae2e430)と同じなので説明省略。

## API作成

```
amplify add api
```
これまたインタラクティブに聞いてくるので回答。

```
? Please select from one of the below mentioned services GraphQL
? Provide API name: AmplifyFunction
? Choose an authorization type for the API Amazon Cognito User Pool
Using service: Cognito, provided by: awscloudformation

 The current configured provider is Amazon Cognito.

 Do you want to use the default authentication and security configuration? Defau
lt configuration
 Warning: you will not be able to edit these selections.
 How do you want users to be able to sign in when using your Cognito User Pool?
Email
 Warning: you will not be able to edit these selections.
 What attributes are required for signing up? (Press <space> to select, <a> to t
oggle all, <i> to invert selection)Email
Successfully added auth resource
? Do you have an annotated GraphQL schema? No
? Do you want a guided schema creation? Yes
? What best describes your project: Single object with fields (e.g., “Todo” with
 ID, name, description)
? Do you want to edit the schema now? Yes
```
ここでエディタが起動されます。
schema.graphqlというファイルが自動生成されているので適宜スキーマ定義を変更します。

以下はスキーマにtitleフィールドを追加した例

```
type Todo @model {
  id: ID!
  name: String!
  description: String
  title: String
}
```

typeに```@model```ディレクティブをつけるとテーブルが作成されます。
スキーマ定義ではその他に様々なディレクティブ(```@key```, ```@auth```, ```@connection```など)が用意されいます。
詳細は[こちら](https://aws-amplify.github.io/docs/cli-toolchain/graphql)を参照。

schema.qraphqlのスキーマ定義が終わったら保存した上でターミナルに戻ります。
```? Press enter to continue```と聞かれているはずなので、enterキーを押します。

最後に以下のコマンドを実行してデプロイします。

```
amplify push
```

以下のように新しく作成される認証とApiのリソースが表示されます。

```

| Category | Resource name           | Operation | Provider plugin   |
| -------- | ----------------------- | --------- | ----------------- |
| Auth     | amplifyfunctiondxxxxxxx | Create    | awscloudformation |
| Api      | AmplifyFunction         | Create    | awscloudformation |
```
このあと、インタラクティブにいくつかの回答（基本全部Yes)していくとデプロイが実行されます。

```
? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target typescript
? Enter the file name pattern of graphql queries, mutations and subscriptions sr
c/graphql/**/*.ts
? Do you want to generate/update all possible GraphQL operations - queries, muta
tions and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply
nested] 2
? Enter the file name for the generated code src/API.ts
```


正常にデプロイが完了したら、AWSコンソールにアクセスしてリソースが作成されていることを確認できます。

AmplifyでAPIを作成すると標準的なCRUD操作に必要なクエリが自動生成されます。
クエリは必要に応じて自分で定義すれば良いですが、簡単なアプリケーションであればこの自動生成されたクエリだけで十分でしょう。

```queries.ts
export const getTodo = `query GetTodo($id: ID!) {
  getTodo(id: $id) {
    id
    name
    description
    title
  }
}
`;
export const listTodos = `query ListTodos(
  $filter: ModelTodoFilterInput
  $limit: Int
  $nextToken: String
) {
  listTodos(filter: $filter, limit: $limit, nextToken: $nextToken) {
    items {
      id
      name
      description
      title
    }
    nextToken
  }
}
`;
```

```mutation.ts
export const createTodo = `mutation CreateTodo($input: CreateTodoInput!) {
  createTodo(input: $input) {
    id
    name
    description
    title
  }
}
`;

...などなど
```

```subscriptions.ts
export const onCreateTodo = `subscription OnCreateTodo {
  onCreateTodo {
    id
    name
    description
    title
  }
}
`;
...などなど
```

## APIを使う
デプロイが完了するとsrcフォルダの直下に「aws-exports.js」ファイルが生成されます。
このファイルにバックエンドの接続先となるAppSyncエンドポイントやリージョン、認証方式などの情報が記録されています。アプリケーションに組み込んで利用する際にはこのファイルを読み込んで利用します。

例えば、以下のような感じ

```API.ts
import awsmobile from './aws-exports';
Amplify.configure(awsmobile)

const App: React.FC = () => {
  return (
      ...snip...
  );
}

```

API呼び出しは以下のような感じ

### Query
（listはデフォルトだと取得10件までなので適宜limitの値を変更）

```ListTodoSample.ts
import { API, graphqlOperation } from 'aws-amplify'
import { listTodos } from './graphql/queries'


//Todoリスト取得する実装抜粋
const result = await API.graphql(graphqlOperation(listTodos, { limit: 1000 })) as GraphQLResult
const query = result.data as ListTodosQuery
if (query.listTodos) {
   const list = query.listTodos.items as Array<CreateTodoInput>
   return list
}
```

### Mutations

```MutationSample.ts
import { API, graphqlOperation } from 'aws-amplify'
import { createTodo } from './graphql/mutations'

//Todo追加する実装抜粋
const input: CreateTodoInput = {
   name: 'hoge',
   description: 'fuga',
   title: 'piyo',
}
const newTodo = await API.graphql(graphqlOperation(createTodo, { input }))
```

### Subscriptions

```SubscriptionSample.ts
import { API, graphqlOperation } from "aws-amplify";
import { onUpdateTodo } from "../graphql/subscriptions";

//更新されたTodoをサブスクライブする実装抜粋
const subscription = API.graphql(graphqlOperation(onUpdateTodo)).subscribe({
        next: (response: any) => {
            const todo = response.value.data.onUpdateTodo as UpdateTodoInput
            //do something
        }
    })

```

# まとめ
ざっくりとamplify add apiを利用したバックエンド構築を試してみました。ものすごく簡単な手順であっという間に作れてしまいますね。今回は単純なテーブル作成のケースをご紹介しましたが、amplifyではschema.graphqlに色々なカテゴリが用意されていて、複雑なシステム構成でも簡単に構築ができるようになっています。
機会があれば、ご紹介したいと思いますが、今回はここまで。