【AWS Amplify】GraphQLのSubscription処理をTypeScriptで書いてみた!!!!

こんにちは!夏が過ぎ風あざみ。どうも僕です🍚🍙🌾

最近僕はJavascriptからTypeScriptに推し変しました!
そんなわけでAWS Amplifyのプロジェクトで、GraphQLのSubscription処理の実装をJSTSで比較してみました!
今回のプロジェクトはAWS Amplify×Reactでつくっています!

Javascript編】プロジェクトの作成

Reactのプロジェクト生成

krmx-demoという名前で作っていきます。

$ npx create-react-app krmx-demo
$ cd krmx-demo

amplify init

$ amplify init
$ yarn add aws-amplify aws-amplify-react

GraphQL APIの追加

Do you have an annotated GraphQL schema?Noを入力します。
テンプレートはSingle object with fieldsを選択してください。
これによりTodoリストのスキーマが自動生成されますので、今回はこれをそのまま利用したいと思います。

$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: krmxdemo
? Choose the default authorization type for the API API key
? Enter a description for the API key: 
? After how many days from now the API key should expire (1-365): 7
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)

amplify push

バックエンドのデプロイをします。このとき、GraphQL API関連のファイルを作成するか聞かれるのでYを入力し、言語にjavascriptを選択してください🥳

$ amplify push
? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target javascript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.js
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscription
s Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2

Javascript編】実装サンプル

App.jsを以下のように編集します。
Todoのレコードの作成イベントをSubscribe(購読)しています。

import React, { useEffect } from "react";
import { onCreateTodo } from "./graphql/subscriptions";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import awsExports from "./aws-exports";

import logo from "./logo.svg";
import "./App.css";

Amplify.configure(awsExports);

function App() {
  useEffect(() => {
    (async () => {
      const subscription = API.graphql(
        graphqlOperation(onCreateTodo)
      ).subscribe({
        next: ({ value: { data } }) => {
          alert(data.onCreateTodo.name);
          console.log(data.onCreateTodo);
        },
        error: (error) => {
          console.warn(error);
        },
      });
    })();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

Javascript編】動作検証

検証するため、createTodoAPIを叩くシェルを作成します。

createTodo.shという名前で以下の通り編集します。
API KEY、endpointの値は$ amplify status コマンドで確認ができます。

script='mutation User {
  createTodo(input: {
    id: \"1\", 
    name: \"テストユーザー\", 
    description: \"テストです。\", 
  }) {
    id
    name
    description
    createdAt
    updatedAt
  }
}
'

script="$(echo $script)" #改行を消して1行にする

curl -H "x-api-key:●●●●●" \
    -H 'Content-Type:application/graphql' \
    -X POST -d "{ \"query\": \"$script\"}" https://▲▲▲▲▲.appsync-api.ap-northeast-1.amazonaws.com/graphql

以下のコマンドで実行権限を付けます。

$ chmod +x createTodo.sh

$ yarn && yarn startでサーバーを起動してhttp://localhost:3000を開いた状態でcreateTodo.shを実行します。
レコードが作成されダイアログが表示されるはずです!!

./createTodo.sh

f:id:mtr-krmx:20210906171412p:plain

【TypeScript編】プロジェクトの作成

続いてはTypeScriptでやってみます😎

Reactのプロジェクト生成

$ npx create-react-app krmx-demo-ts
$ cd krmx-demo-ts

amplify init

$ amplify init
$ yarn add aws-amplify aws-amplify-react
$ yarn add typescript @types/node @types/react @types/react-dom

GraphQL APIの追加

$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: krmxdemots
? Choose the default authorization type for the API API key
? Enter a description for the API key: 
? After how many days from now the API key should expire (1-365): 7
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, de
scription)

amplify push

amplify pushコマンドを実行します。Choose the code generation language targettypescriptを選択します。
APIに関連する型が定義されたsrc/API.tsというファイルが自動生成されます。

$ amplify push
? 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 src/gra
phql/**/*.ts
? Do you want to generate/update all possible GraphQL operations - queries, mutations
 and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply neste
d] 2
? Enter the file name for the generated code src/API.ts

【TypeScript編】実装サンプル

App.jsの名前をApp.tsxに変更して、以下のように編集します。
OnCreateTodoSubscriptionという型を使用するのがポイントですね。

今回の例ではレコード作成のSubscriptionについてですがsrc/API.tsにはGraphQLのスキーマに対応したSubscription/Mutation/Queryの型が定義されています。 ナイスですね🎥

import React, { useEffect } from "react";
import { onCreateTodo } from "./graphql/subscriptions";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import awsExports from "./aws-exports";
import { OnCreateTodoSubscription } from "./API";

import logo from "./logo.svg";
import "./App.css";

Amplify.configure(awsExports);

type OnCreateTodoSubscriptionData = {
  value: { data: OnCreateTodoSubscription };
};

function App() {
  useEffect(() => {
    (async () => {
      const subscription = API.graphql(graphqlOperation(onCreateTodo));
      if ("subscribe" in subscription) {
        subscription.subscribe({
          next: ({ value: { data } }: OnCreateTodoSubscriptionData) => {
            if (data.onCreateTodo) {
              alert(data.onCreateTodo.name);
              console.log(data.onCreateTodo);
            }
          },
          error: (error) => {
            console.warn(error);
          },
        });
      }
    })();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

【TypeScript編】動作検証

Javascriptのときと同様に検証してみます。

script='mutation User {
  createTodo(input: {
    id: \"1\", 
    name: \"TSテストユーザー\", 
    description: \"TSテストです。\", 
  }) {
    id
    name
    description
    createdAt
    updatedAt
  }
}
'

script="$(echo $script)" #改行を消して1行にする

curl -H "x-api-key:●●●●●" \
    -H 'Content-Type:application/graphql' \
    -X POST -d "{ \"query\": \"$script\"}"  https://▲▲▲▲▲.appsync-api.ap-northeast-1.amazonaws.com/graphql
$ chmod +x createTodo.sh
$ yarn && yarn start
 →http://localhost:3000をブラウザで開く
./createTodo.sh

f:id:mtr-krmx:20210906181334p:plain

みなさんもダイアログが表示されましたか?

Subscriptionを使うと面白いWebアプリケーションが作れるので、みなさんも是非トライしてみてください💪💪💪