【Day9】フロントエンドとバックエンドをそれぞれデプロイする

## はじめに

勉強とアウトプットを兼ねて、Webアプリ開発の記録を記事にしてみます。

個人のメモ的な側面が強いです。
Web開発初心者すぎて至らぬところだらけだと思いますが、暖かい目で見ていただければ幸いです。

↓ これまでの内容 ↓
[【Day0】アプリが完成するまで毎日投稿](https://qiita.com/midorigame/items/f9b9a445c945b4a837b1)
[【Day1】開発環境を考える](https://qiita.com/midorigame/items/e26344599e2ffaa22033)
[【Day2】開発環境を構築する、、、はずでした](https://qiita.com/midorigame/items/3f57f2691a8e1074adb8)
[【Day3】まずはフロントだけ開発環境を構築する](https://qiita.com/midorigame/items/9de27ba72aaef504a833)
[【Day4】バックエンドの開発環境を整えつつ、マルチコンテナ対応のDevcontainerにする](https://qiita.com/midorigame/items/5b95374cd85f715a6498)
[【Day5】お試し実装！ファイルをアップロードしてバックエンドで処理する](https://qiita.com/midorigame/items/9663f0063b95b501c08a)
[【Day6】Docker Desktopが起動しなくなり泣きながら原因調査する](https://qiita.com/midorigame/items/d07df1caf05267d0609d)
[【Day7】画像にフレームとExif情報を付けてみる](https://qiita.com/midorigame/items/e2d85ce8dd7a5bcb5daf)
[【Day8】フロントに表示する画像のサイズを小さくする](https://qiita.com/midorigame/items/f7f5f9b14fb79259c716)

## 前回やったこと

フロントに表示させる画像を小さくしてUIをちょっとだけ良くしました。

## 今回やったこと

フロントエンドをVercelに、バックエンドをRenderにデプロイすることで、外部サーバーでも疎通可能にしました！

まだ自分のやりたい機能をすべて実装できてないしUIもまだまだですが、すでに簡単な機能は実装できているので、試しにデプロイしてみます！

フロントエンドとバックエンドでデプロイするにあたってやったことを書いていきます。

## フロントエンド

フロントエンドはReactで書いています。
今回はVercelにデプロイしました。
https://vercel.com/

### APIのURLを変更

開発環境では`http://localhost:8000/upload-image`にしていましたが、デプロイ後は`<デプロイ先のドメイン>/upload-image`にする必要があります。

そこでAPI_URLを簡単できるようにAPIを投げる部分を以下のように変更しました。

```react:ImageUploader.tsx
      const response = await axios.post(
        import.meta.env.VITE_UPLOAD_IMAGE_API_URL, // "http://localhost:8000/upload-image"
        formData,
        {
          responseType: "blob",
        }
      );
```

`import.meta.env.VITE_UPLOAD_IMAGE_API_URL`ではReactプロジェクトのルートに置いた.envファイルに定義した環境変数を取得することができます。

```text:.env
VITE_UPLOAD_IMAGE_API_URL="<Renderにデプロイ後のURL>/upload-image"
```

今回はViteでReactのプロジェクトを作成したため、環境変数の接頭語はVITE_にする必要がありました。


↓　こちらの方の説明記事がとても分かりやすかったです！ありがとうございます！！

https://ralacode.com/blog/post/use-env-variables-in-react/

### Vercelにデプロイ

VercelはGitリポジトリを選択するだけで、そのリポジトリを自動的デプロイしてくれます。
コミットしたときも自動的に更新してくれます！便利！！

デプロイ時の設定は以下のようにしました。

- ルートディレクトリはfrontend
- Build Commandはnpm run build
- Install Commandはnpm install
- 環境変数にVITE_UPLOAD_IMAGE_API_URLを追加
    - RenderにデプロイしたFast APIのURLを指定しました
    - 例：`https://<hogehoge>.onrender.com/upload-image`

## バックエンド

バックエンドはPythonのFast APIで書いてます。
今回はこちらをRenderにデプロイしました。
https://dashboard.render.com/

### CORSの設定

APIを外部のサイトから使用できるようにするためにはCORSの設定が必要です。

> オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) は、 HTTP ヘッダーベースの仕組みを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
https://developer.mozilla.org/ja/docs/Web/HTTP/Guides/CORS

要は、「あらかじめ設定したドメインからのリクエストしか受け付けないようにする」仕組みみたいです。

今回は以下のように設定しました。

```python:main.py
ALLOW_ORIGIN = os.environ['ALLOW_ORIGIN']
app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000", ALLOW_ORIGIN],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
```

ALLOW_ORIGINという環境変数の値をCORSの許可リスト？に追加しています。
また、開発中にも使えるために`http://localhost:3000`も一緒に追加しています。

### Renderにデプロイ

RenderもVercelと同じようにGitリポジトリを選択するだけで、そのリポジトリを自動的デプロイしてくれます。
コミットしたときも自動的に更新してくれます！便利！！

Renderには以下の設定でデプロイしました。

- デプロイ形式はWeb Service
- ルートディレクトリはbackend
- Build Commandは`pip install -r requirements.txt`
- Start Commandは`uvicorn app.main:app --host 0.0.0.0 --port 8000`
- 環境変数にALLOW_ORIGINを追加
    - VercelにデプロイしたReactのURLを指定しました
    - 例：`https://<hogehoge>.vercel.app`

※ Renderにデプロイしたサービスは一定時間アクセスしないと停止してしまい、次回起動時に時間がかかってしまうのは注意です！

## デプロイ

デプロイしたらこんな感じになりました！
良い感じかも！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307348/2a462682-5801-4601-bf4d-cc2c3f4f8cdc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307348/8a8b0295-204b-4d62-a909-60de1a6855c4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307348/db834356-c63f-4efa-824f-6ef10db56a3e.png)

Gif撮影ツールを入れてなくてスクショ連投してしまいました。

## おわりに

今までRenderしか使ったことなくて、Vercelは初めて使いましたが直観的かつ軽量にデプロイできるのは便利だなぁと思いました。

実際にデプロイして他のブラウザでも動くようになると嬉しいですね！
この調子でどんどん機能実装していくぞ～