React+Django+AWSでペットの成長をサポートするアプリを開発したのでTipsをまとめた

![FireShot Capture 011 - biby diary - biby-diary.studio.site.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243199/878c95ab-12f9-45c7-f46f-61805a64e577.png)

biby diary
https://biby-diary.studio.site/


本日、ペットの成長を記録できるアプリ「biby diary」をリリースしました。
biby diaryは日々のペットの成長を記録できるほか、家族間でのペットの情報を共有することができます。
さらにbiby検索から動物病院を検索することもできるので、緊急時などにお近くの住所から迅速に動物病院を見つけることもできます。
スマホ推奨で、PWAにも対応しているのでブラウザからホーム画面に追加することで快適にご利用いただけます。
追加する際はこちらのリンクから追加してください。
https://diary.biby.live

アーキテクチャーにはDjango、React、AWSを採用しており、これらの技術で実務にあたられている方や採用を検討している方の参考になればと思いまとめました。
もし紹介する内容以外でベストプラクティスがあれば、ぜひコメント欄へ共有いただきたいです。

#目次
[アーキテクチャ詳細](#アーキテクチャ詳細)
[ReactのTips](#reactのtips)
[DjangoのTips](#djangoのtips)
[ngrok](#ngrok)
[今後の計画](#今後の計画)

#アーキテクチャ詳細

全体のシステムはこのような図になっています。
![biby-arch (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243199/b387aea9-1dd5-7dba-c3e7-dd4c8e217cd7.png)

biby diaryはReact+TypeScriptとDjangoで開発しました。サーバーはAWSのものを使用しており、フロントエンドにはamplify、バックエンドにはEC2を使用しています。
amplifyを使うことでURLのSSL化やデプロイの設定などを簡単に行うことができます。
ドメインはお名前.comで取得しているのですが、ネームサーバーをAWSに向けておけばCNAMEなどの設定も自動で行ってくれるので非常に楽でした。
バックエンドにEC2を使うことで、CodeDeployとCodePipelineを使って容易に自動デプロイの設定ができます。

フロントエンドとバックエンドを分けたのは、後々スマホアプリ化も検討しているため、あえて分離しています。
現在はWebブラウザだけですが、PWAにも対応しているのでホーム画面にアプリを追加していただければアプリのような操作感でお使いいただけます。

今回初めてAWSを使用しましたが、ほかのクラウドサービスと比べて非常に使いやすい印象でした。
さすがクラウドサービス市場のトップです。ちなみに2位はAzureです。
G○Pだとなぜそうなる？みたいことになりがちだったので、これからはAWSを推していこうと思います。

#ReactのTips

Reactは以前から使用した経験があったのと、Adobeが提供しているReact Spectrumを使ってみたかったこともあり採用しました。
React Spectrumについては本記事では詳しく説明しないので、別の機会にまとめようと思っています。

##Reactでクッキーを操作する方法

biby diaryではログインした時にAPIにリクエストを送るためのトークンを発行しているのですが、そのトークンを持っておくためにクッキーを使用しています。
Reactにはreact-cookiesというクッキーの操作が簡単にできるパッケージがあります。
https://github.com/reactivestack/cookies/tree/master/packages/react-cookie

###利用例

まずはアプリ全体をCookiesProviderラップします。

```jsx:
import React from 'react';
import App from './App';
import { CookiesProvider } from 'react-cookie';

export default function Root() {
  return (
    <CookiesProvider>
      <App />
    </CookiesProvider>
  );
}
 ```

アプリを登録する場合は下記のようになります。

```jsx:aaa
import React from 'react';
import { useCookies } from 'react-cookie';

import NameForm from './NameForm';

function App() {
  const [cookies, setCookie] = useCookies(['name']);

  function onChange(newName) {
    setCookie('name', newName, { path: '/' });
  }

  return (
    <div>
      <NameForm name={cookies.name} onChange={onChange} />
      {cookies.name && <h1>Hello {cookies.name}!</h1>}
    </div>
  );
}

export default App;

```

useCookiesを使用したい箇所でインポートし、`const [cookies, setCookie] = useCookies(['name']);`でクッキーを登録できるようにします。
実際の登録は、`setCookie('name', newName, { path: '/' });`となっており、pathオプションを指定することでクッキーの保存対象にしたいページを選択できます。`/`を指定した場合はアプリのページ全てに対してクッキーを保存することになります。

ログアウト時などにクッキーを削除したい場合は、`removeCookie`を使用します。
removeCookieにもpathオプションを指定することができ、`removeCookie('name', { path: '/' })`としておくことでページ全体に対して選択したクッキーを削除できます。
あえて`{ path: '/' }`を指定しておくことをおすすめします。

##環境変数の設定

Reactの構築にはCreate React Appを用いており、Create React Appにはデフォルトで環境変数を供給する機構が備わっています。

使い方は簡単でプロジェクト直下に.envファイルを作成し、REACT_APP_をプレフィックスにした変数を入れておくことでReactアプリ内で呼び出すことができます。
呼び出す時はprocess.env.REACT_APP_[変数名]で変数を取得できます。

##利用例

```.env
REACT_APP_TEST="test"
```

環境変数を呼び出す時はこのようになります。

```js
const test = process.env.REACT_APP_TEST;
```

###amplifyでの環境変数設定

.envファイルは機密情報を含める場合もあるため`.gitignore`に入れておくことが望ましく、デプロイ時に.envを生成する必要があります。

amplifyでは管理画面のサイドバーにある環境変数から設定を行い、同じくサイドバーのビルドの設定から.envファイルの生成コマンドを追記します。

環境変数設定画面を開くとこのような画面が出てきます。
変数と値をそれぞれ入力します。

![FireShot Capture 008 - AWS Amplify Console - us-east-2.console.aws.amazon.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243199/b6029c52-657c-0f34-00ce-cee0d4e541f9.png)


続いてビルドの設定を開くと、下記のようなビルド設定が表示されていると思います。

```yml:amplify.yml
version: 1
frontend:
  phases:
    preBuild:
      commands:
        - yarn install
    build:
      commands:
        - yarn run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
```

.envの生成はbuild>commandsに`- echo "REACT_APP_TEST=$REACT_APP_BACKEND_TEST" >> .env`を追記します。
同じ画面からymlファイルの編集ができるので、そのまま追記できます。

##画像アップロード

画像アップロードに手こずってしまったので、同じような境遇に会った方、会われるであろう方に向けてTipsを紹介しておきます。
基本的にAPIリクエスト時にデータを渡すときは、JSON形式にしているのですが画像をアップロードする時にどうしてもJSONではリクエストに失敗するということがありました。
調べるとJSON形式でもファイル送信ができるみたいな情報が出てきたのですが、実現できなかったのでファイルアップロードによく使われるmultipart/form-data形式を使うことにしました。
最終的にmultipart/form-dataで無事に画像ファイルは送信できるようになったのですが、もう一つ躓いたポイントがあり、リクエストヘッダのcontent-typeに明示的にmultipart/form-dataを指定するとリクエストに失敗する現象が発生しました。
理由はいまだにわからないので、もし分かる方いたら教えてください。

#DjangoのTips

DjangoにはDjango Rest FrameworkというREST APIを実装できるパッケージがあるのですが、これがかなり使いやすく容易にAPIを開発できるのでDjangoを採用しました。
デフォルトで管理画面が付いている点も理由の1つです。

##CORS問題

API開発でやっかいなのが、CORS問題です。CORSは同一生成元ポリシーと呼ばれるブラウザのセキュリティ仕様で、あるサーバーにWebからリクエストを送る時に同じドメインであればエラーは起きないのですが、違うドメインからのリクエストは脆弱性から守るために拒否されます。

このサイトがわかりやすくCORS問題について説明しているので、気になる方はご参照ください。
https://coliss.com/articles/build-websites/operation/work/cs-visualized-cors.html

CORS問題を解消するにはバックエンド側でCORSの制御をする必要があります。
corsheadersというパッケージを使うことで、CORS問題を片付けることができます。
https://github.com/adamchainz/django-cors-headers

##環境変数
Djangoは環境を立ち上げた時にシークレットキーが作られます。このシークレットキーはユニークIDの生成などに使用されるので、gitで管理するようなことはしたくありません。
そのため、環境変数で持っておくことが望ましいです。
Djangoには、django-environという環境変数を設定するためのパッケージがあります。
https://github.com/joke2k/django-environ

このパッケージを使うことで容易に環境変数の設定ができます。

###使い方

プロジェクト直下に.envファイルを作成し変数を追記していきます。

具体的にはこのような形で追記します。
代入する値はダブルクオートなどで囲む必要はないのでご注意ください。

```
DEBUG=on
SECRET_KEY=your-secret-key
```

呼び出す時はこのようになります。

```py:settings.py
import environ
env = environ.Env(
    # set casting, default value
    DEBUG=(bool, False)
)
# reading .env file
environ.Env.read_env()

# False if not in os.environ
DEBUG = env('DEBUG')

# Raises django's ImproperlyConfigured exception if SECRET_KEY not in os.environ
SECRET_KEY = env('SECRET_KEY')
```

#ngrok

アプリを開発しているとスマホでも実際に挙動を確認したいということがあると思うのですが、フロントエンドとバックエンドを分離していると、ローカル環境ではAPIのドメインがlocalhostなため確認できません。
フロントにはアクセスできるけどバックエンドにはつながらないといったことになると思います。
このときにおすすめなのがngrokという開発ツールで、ngrokを使用することで一時的に作られるドメインとローカルのドメインを結びつけることができ、他のデバイスからアクセスすることができます。
https://ngrok.com/

開発途中のアプリをngrokを使ってクライアントに見てもらうこともできるので、実務でも大活躍します。

会員登録なしでも使用することができるのですが、その場合一時的に発行されるドメインの有効期限が決まっています。
有効期限なしで使用したい場合は、無料プランの登録もできるので会員登録しておくことをおすすめします。

起動はターミナルを開いて`ngrok http ポート番号`と入力するだけなので簡単にアプリを外部に向けて公開できます。

#今後の計画
biby diaryはまだまだ未完成なので、継続的に開発をしていきます。
今は無料プランしかないので近々有料プランを追加する予定しているほか、bibyユーザーがペットへの寄付を外部に募ることができる機能も考えています。

追加して欲しい機能も絶賛募集中なので、ぜひご連絡ください。本記事のコメント欄もしくは、こちらのお問い合わせフォームからご要望いただくこともできます。
https://forms.gle/EJdXYLNWbeLfCccm9

形だけですがロードマップを公開しているので、気になる方はぜひご覧ください。
https://nisyuu.notion.site/5bead4691e344d6b946a09f9aa8c7d1f?v=3fccb1b559ef4c27ab0872db33a95690!%5BFireShot