apollo+typescript+codegen+reactでファイルアップロード

https://qiita.com/advent-calendar/2021/graphql
GraphQL Advent Calendar 2021 12/18担当の記事です。

## 自己紹介
みなさま初めまして、ひらさです。
現在[クーガー株式会社](https://couger.co.jp/)でフロントエンドとバックエンドを主に担当しているエンジニアです。
レイチェルというバーチャルヒューマンエージェントを作っている会社です。

絶賛エンジニア募集中ですので、興味ある方はぜひ。
https://couger.co.jp/news/career/


## 本記事について
サーバサイド： `Typescript`, `apollo-server`, `express` 
フロントエンド： `Typescript`, `React`, `apollo-client` 
graphqlスキーマ定義生成: `graphql-codegen`
のセットで、ファイルアップロード機能のfrontとserverを実装したので、その解説記事になります。

完成したソースコードはこちらになります(スターつけてくれると嬉しい)。
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient
以下、このリポジトリの解説になります。

## 基礎知識
### そもそもgraphqlとは
https://qiita.com/shotashimura/items/3f9e04b93e79592030a4
サーバ側との通信に型情報(スキーマ)をつけれるとか、複数のエンドポイントを一回で叩けるとか、メリットたくさん。

### codegenとは
https://techlife.cookpad.com/entry/2021/03/24/123214
こちらの記事でめちゃくちゃ分かりやすく解説して下さっていますが、
要は.graphqlのファイルを元に、typescriptの型や関数、クラスなどが記述されたファイルを生成してくれるものです。

### reactとは
https://qiita.com/rgbkids/items/8ec309d1bf5e203d2b19

### expressとは
https://qiita.com/nkjm/items/723990c518acfee6e473

### apolloとは
https://qiita.com/jintz/items/4ddc6bf4f95238eff5e9

## インストール方法
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient
このリポジトリのREADME.mdを参照
## 使い方
上記の構築手順に従って進めて `http://localhost:3050/` にアクセスすると、このような`センスのない雑な画面`が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105352/b8929021-5721-1ffa-686f-236858978e80.png)
### ヘルスチェックで疎通確認
まずはサーバ側とちゃんと通信ができるかの確認で、右側のヘルスチェックの「実行」ボタンを押して、結果が「成功」と表示されればOKです。
デベロッパーツールを見ても疎通できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105352/a6785e2a-fdde-cc7d-f9e0-703aaa8a902c.png)
### ファイルアップロードの確認
次に本題のファイルアップロードができるかの確認です。
左側のファイルアップロードテストの「ファイルを選択」で適当なファイルを選択し(サイズが大きすぎるとアップロードできない恐れ馬あります)、「アップロード実行」をクリック。
結果が「成功」と表示されればOKです。アップロードされたファイルは、 `/server/upload_files` に保存されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105352/42069943-da2e-cde4-9992-7289daa185cb.png)

## いろいろ説明
### ルートディレクトリ構成
|ディレクトリ名|説明|
|:--|:--|
|/core|共通で使用するファイルを格納。|
|/front|front側のソースコード。react, typescriptで実装|
|/server|server側のソースコード。nodejs, express, typescriptで実装|

### /coreの説明
こちらに、frontとserver共通で使用する.graphqlファイルが格納されています。
graphqlのスキーマを更新したい場合は、こちらの.graphqlファイルを更新した後、

```
$ (cd core && yarn install)
$ (cd core && yarn generate-server)
$ (cd core && yarn generate-front)
```

このように実行すれば `graohql-codegen` ツールを使って.graphqlファイルからそれぞれtsファイルが作成されます。
frontとserverはこれらのジェネレートされたファイルを使って、tsで実装していきます。
frontとserverで必要な型定義が違いますので、 `front_codegen.yml` と `server_codegen.yml` で設定ファイルを分けています。

それぞれ
`server -> /server/src/web_server/graphql/types/ApolloServerTypes.ts`, 
`front -> /front/src/types/graphql/ApolloClientTypes.ts`
に生成されます。


## /frontの説明
react, react-redux, react-router-domで構成されています。

|ディレクトリ名|役割|
|:--|:--|
|data_sources|データの取得先をまとめたもの、ApolloClientはこちらに格納される。|
|pages|routerから呼ばれる大元のコンポーネント|
|router|routerの設定|
|stores/actions|storeを操作するActionをまとめたもの。pagesから呼ばれ、データ取得や更新などをおこなった後、storeに結果を反映する。|
|stores/state|store(状態)の構成や設定。|
|types|型を管理。scalars.tsはgraphqlに追加するスカラー型を定義している。|
|utils|汎用ライブラリを格納。|

frontの場合は、ファイルは `File` という型情報になりますので、
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/front/src/types/graphql/scalars.ts#L1
こちらのscalarsでgraphqlのファイルとブラウザ上のFileの型を紐づけています。

実際のファイルアップロードの処理はこちらでおこなっており、 `graphql-codegen` で生成した関数を使ってアップロード処理を行なっています。
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/front/src/stores/actions/FileUploadActionHook.ts#L20

ファイルアップロードの場合、apolloClientだと `Link` を切り替える必要があるみたいで、https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/front/src/data_sources/graphql/AppApolloClient.ts#L61
こちらで切り替え処理を入れました。


## /serverの説明
|ディレクトリ名|役割|
|:--|:--|
|domain/controllers|処理の大まかな流れをコントロールする|
|domain/services|機能を提供する。実際のファイルの保存処理などはここに書いている。|
|utils|汎用ライブラリを格納。|
|web_server/apis|apiのエンドポイントを定義。|
|web_server/graphql|graphqlの型定義を格納。scalars.tsはgraphqlに追加するスカラー型を定義している。|
|web_server/server.ts|grapqlサーバのインスタンスを生成して返す|
|index.ts|サーバを起動している|

サーバの場合、`graphql-upload` ライブラリとscalarを紐づける必要があるので、こちらで定義してます。
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/server/src/web_server/graphql/scalars.ts#L3

ファイルアップロードのresolverはこちらで定義していて、ここがファイルアップロードAPIの最初の実行部分になります。
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/server/src/web_server/apis/resolvers/FileUploadResolver.ts

その後、 controller -> service を情報が渡り、
https://github.com/hirasaki1985/ApolloFileUploadServerAndClient/blob/main/server/src/domain/services/FileUploadService.ts#L40
ここでファイル保存をしています。



大雑把に解説しましたが、以上になります。