リモートワークで運動不足なのでオンライン駅伝を主催した話し

# この記事はなに？

趣味でやっているランニングサークルでオンライン駅伝をやっているので、記録集計用の駅伝アプリを作ってみました。
全般的には、Amplify+Reactで作ってみたポエムです。（設計に関する深い洞察とかはございません。汗）

## リモートワーク下の運動不足防止のため、オンライン駅伝を主催した経緯
当社はリモートワークが中心になっているので、**意識しないと1日の歩数が二桁!**とかそういうことになってしまいます。
そこで、オンラインのランニングサークルを主催し、隔月でオンライン駅伝を開催することにしました。（去年の11月から）

だいたい参加者は20〜30人です。4人で1チームを作り、通常は1人が5km走ります。

## これってIT技術ブログなの？

大丈夫です。こっから技術の話しに徐々になります。
当初は、スプレッドシートで記録集計や順位計算をしていたのですが、これが面倒な訳です。
なにしろ **「業務外でスプレッドシート触りたくないでござる！」**

という訳でせっかくなのでAmplify＋Reactで記録集計用の簡易システムを構築してみました。

# システム概念図

ランニングサークル自体はDiscordの某サーバーの1チャンネルとして運営されていて、ランナーの記録は、DMで私に報告してもらっています。
図で言うと、Communityという部分です。

現状は、僕がシステムへの入力を一括して実施し、記録集計をおこなっています。
その後、表彰状を手作りし、Zoomミーティングで表彰式＆打ち上げを行うという感じです。

![arch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/273eccac-fb2f-0167-8819-e82dfb849814.png)

将来構想として、ランナーにWebアプリ（スマホ上にはPWAで展開）で記録を入力してもらい、表彰式資料も自動生成したいのですが、そこまでの必要性があまりないので、将来構想のままで終わるかもしれません。

#システムの中身の説明

システムの中身の説明は、AWS公式のチュートリアルなどの資料に譲りますが、ここでは、２点だけ、感想めいたことを書いておこうと思います。  
それぞれ、詳細は後述します。

1. AmplifyCLIは慣れが必要（当たり前ですね）  
なので、チュートリアルをまずやったら「amplify delete」でCloudの資源を消して、もう1回くらいやることをオススメします。

1. GraphQLを知らなすぎた
実際に使う機会がなく、存在だけは知っていましたが、いざとなると何がどうなっているんだ！？という感じでした。知らないことをやるのは楽しいですが、今回は駅伝スケジュールに間に合わせる都合でかなりダーティーなソースコードになっております。

# とにかくAmplifyを触ってみよう！

公式のチュートリアル入り口
https://docs.amplify.aws/start/

チュートリアルは日本語版でなく、英語版でやるのが良いと思います。
Reactだけでなく、Vue、Angular、Android、iOS、Flutterなどもあります。
それぞれに少しずつ内容が違うようですが、概ね、Todoアプリを作って、認証機能（Cognito）を組み込むような部分は共通だと思います。  
ここから先は、Reactを例にして進めます。

## AmplifyCLIの躓きポイント（私だけかも？）

### Prerequisites
https://docs.amplify.aws/start/getting-started/installation/q/integration/react/

このページで、必要なものをインストールし、「amplify configure」を行います。
AWSに慣れていないとここも難しいかもしれません。

:::note warn
Administrator権限のIAMユーザーを作成し、ACCESS_KEYの払い出しなどが必要になります。（既存IAMも利用可）
要するに、かなり強い権限のIAMユーザーを払い出すので、ACCESS_KEYなどの管理は十分に気をつけてください。
:::

ここは、一度設定しておくと二度目以降は省略可能です。

### Set up fullstack project 
https://docs.amplify.aws/start/getting-started/setup/q/integration/react/

Reactをやったことがあれば、難しいところはないと思います。
「amplify init」コマンドは、特にこだわりがなければ、デフォルトのままで進めて良いと思います。

このタイミングで、AWS上に、IAMロールとS3Bucket（DeploymentBucket）が作成されます。
AmplifyコマンドがCloudFormationのラッパーなので、何が生成されているか？というのは、CloudFormationのStackを確認するとわかります。（都度、Stackを覗いてみると動作が分かって理解が深まると思います）

### Connect API and database to the app
https://docs.amplify.aws/start/getting-started/data-model/q/integration/react/

ここは個人的には一番戸惑いました。
事前の心構えとして、APIの設計をざっとでもやっておくと良いと思います。
**ハイライト？はSchemaの編集を今する？？って聞かれるところです。**
これは後回ししても大丈夫なんですが、Cloudにpush（Deploy）する前には、やっておく必要があるので、あらかじめ心の準備をしておくことが大事です。

```bash
% amplify add api
? Select from one of the below mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or continue Name: reactamplified3
? Provide API name: myapi
? Here is the GraphQL API that we will create. Select a setting to edit or continue Authorization modes: API key (de
fault, expiration time: 7 days from now)
? Choose the default authorization type for the API API key
? Enter a description for the API key: demo
? After how many days from now the API key should expire (1-365): 7
? Configure additional auth types? No
? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)

⚠️  WARNING: your GraphQL API currently allows public create, read, update, and delete access to all models via an API Key. To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql/authorization-rules

GraphQL schema compiled successfully.

Edit your schema at /Users/akiraabe/Documents/practice/amplify/react-amplified3/amplify/backend/api/myapi/schema.graphql or place .graphql files in a directory at /Users/akiraabe/Documents/practice/amplify/react-amplified3/amplify/backend/api/myapi/schema
? Do you want to edit the schema now? (Y/n) 
```

上のPromptの最後の「Do you want to edit the schema now?」 に関しては、素直にYを押してみましょう。
schema.graphqlというファイルが選択したエディター（ここでは、VSCode）で開きます。
![Screen Shot 2021-12-20 at 11.22.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/659b6d0b-0fc4-3b09-91a0-8d5b9503f791.png)

ちなみに、駅伝アプリの場合には、スキーマは以下のように変更しています。

```graphql:schema.graphql
# This "input" configures a global authorization rule to enable public access to
# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules
input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!

type Record @model {
  id: ID!
  name: String!
  discordId: Int!
  time: Int!
  turn: Int!
  team: String!
  result: String!
  description: String
}
```

### この後はチュートリアルに沿って進めてみてください。
なんか困ったら、Discordのユーザーグループで聞いてみるといいと思います。（雑ですいません）
https://discord.com/invite/jWVbPfC


## GraphQLを知らなすぎた

チュートリアルもRESTでなくGraphQLが標準になっています。
従ってGraphQLを選択した訳ですが、GraphQLどうやって使うん？というのが分からなさすぎました。

ひとまず、Amplifyにより自動生成された「queries.js」のlistRecordsを眺めてみます。

```javascript:queries.js
export const listRecords = /* GraphQL */ `
  query ListRecords(
    $filter: ModelRecordFilterInput
    $limit: Int
    $nextToken: String
  ) {
    listRecords(filter: $filter, limit: $limit, nextToken: $nextToken) {
      items {
        id
        name
        discordId
        time
        turn
        team
        result
        description
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;
```

どうやら、filterで検索条件を指定するようです。SQLっぽいことはどうやるんだろう！？頑張れ来年の自分！！
今年のところは、ダサくても、駅伝の開催を優先し、開催回（time）でフィルタリングして、走順、チーム順にSortする処理を書いてみました。（コードの一部を抜粋）

```js:AllRecordsBoard.js
function AllRecordsBoard() {
  const [records, setRecords] = useState([]);

  useEffect(() => {
    fetchRecords();
  }, []);

  async function fetchRecords() {
    console.log("fetchRecords is invoked");
    let filter = {
      or: [{ time: { eq: TIME } }],
    };

    const apiData = await API.graphql({
      query: listRecords,
      variables: { filter: filter },
    });

    apiData.data.listRecords.items.sort((a, b) => {
      if (a.turn + a.team > b.turn + b.team) {
        return 1;
      } else {
        return -1;
      }
    });

    console.log(apiData);

    setRecords(apiData.data.listRecords.items);
  }

  return (
  // 以下略
```

## まとめ（総合的な感想）
Amplifyで作ったものを現時点でプロダクション環境で使うというのはちょっと想像できませんが、
https://aws.amazon.com/jp/blogs/news/extend-amplify-backend-with-custom-aws-resource-using-aws-cdk-or-cloudformation/
カスタム機能でバックエンドを拡張するなど、どんどん進化しています。

数年前には、恥ずかしながら、ECS（コンテナオーケストレーション）なども本番で使うイメージはなかったですが、今では普通に使っています。
なので、数年後にはAmplifyも普通に使っているかもしれません。今後も色々とウォッチして、いきなり本業では使えなくても、趣味として色々使ってみようかなぁと思っています。

## おまけ
駅伝アプリの全体ソースは恥ずかしいレベルですが、一応アップしておきます。

https://github.com/akiraabe/amplified-relay