├── .gitignore ├── README.md ├── assets ├── applicatio_home.png ├── bootcamp_infra_architecture.jpg ├── bootcamp_infra_list.jpg ├── create_user_table.png ├── create_videos_table.png ├── enable_email_auth.png ├── execute_user_mutation.png ├── firebase_authentication.png ├── firebase_config.png ├── firebase_config_api_key.png ├── firebase_config_storage.png ├── firebase_config_storage_rule.png ├── firebase_config_web_app.png ├── firebase_console.png ├── firebase_create_analytics.png ├── firebase_create_pendeing.png ├── firebase_create_project_name.png ├── firebase_pricing.png ├── firebase_project_console.png ├── firebase_public_env.png ├── firebase_storage_console.png ├── firebase_storage_region.png ├── firebase_storage_rules_edit.png ├── firebase_storage_rurles.png ├── firebase_web_create.png ├── frequently_used_columns.png ├── get_header_username.gif ├── google_login.png ├── graphql_api_architecture.png ├── graphql_fetch_user.png ├── hasura_api_secretpoint.png ├── hasura_create_heroku.png ├── hasura_fetch_user.png ├── hasura_login.png ├── hasura_lp.png ├── hasura_select_mutation.png ├── hasura_success_db.png ├── hasura_table_home.png ├── heroku_login.png ├── insert_users_data.png ├── login_signup.png ├── rest_fetch_user.png ├── restfull_api_architecture.png ├── run_codegen_scripts.gif ├── step1_firebase_setup.png ├── step2_firebase_api_key.png ├── step3_firebase_login.png ├── user_insert_query.png ├── user_mutation_insert.png ├── user_query_explorer.png ├── users_test_column.png ├── users_track.png └── watch_page.png ├── graphql ├── mutation │ └── InsertUser.graphql └── query │ └── users.graphql ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json ├── robots.txt └── static │ ├── no-image.jpg │ ├── production ID_4763824.mp4 │ └── yt_logo_rgb_light.png ├── script └── codegen.js ├── src ├── GlobalStyle.ts ├── Route.tsx ├── components │ ├── Logo │ │ └── index.tsx │ ├── VideoCard │ │ ├── HeaderTitle │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── SubHeaderContent │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── style.ts │ └── VideoHorizontalCard │ │ ├── index.tsx │ │ └── styles.ts ├── index.tsx ├── layouts │ ├── Home │ │ ├── index.tsx │ │ └── style.ts │ ├── SideLessHome │ │ ├── index.tsx │ │ └── styles.ts │ └── Simple │ │ ├── index.tsx │ │ └── style.ts ├── pages │ ├── ForgetPassForm │ │ ├── index.tsx │ │ └── style.ts │ ├── Home │ │ └── index.tsx │ ├── Login │ │ ├── index.tsx │ │ └── style.ts │ ├── Signup │ │ ├── index.tsx │ │ └── style.ts │ ├── Upload │ │ ├── UploadForm │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── VideoSelector │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── index.tsx │ │ └── style.ts │ └── Watch │ │ ├── VideoPlayerCard │ │ ├── index.tsx │ │ └── style.ts │ │ ├── index.tsx │ │ └── style.ts ├── react-app-env.d.ts ├── templates │ ├── DashboardHeader │ │ ├── SearchBar │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── index.tsx │ │ └── style.ts │ └── Sidebar │ │ ├── index.tsx │ │ └── style.ts └── utils │ ├── Firebase │ ├── config.ts │ ├── forgetPass.ts │ ├── login.ts │ ├── signout.ts │ ├── signup.ts │ └── storage.ts │ └── graphql │ ├── .gitkeep │ └── generated.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | .env.local 18 | .env.development.localo 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReactBootcamp 開発ドキュメント 2 | 3 |
4 | 前回までのBootcamp 5 | 6 | > 次回までの目標 7 | > 8 | > - [x] React のデザインシステムを理解し、アプリの見た目を整えよう! 9 | 10 | > 今週のやることリスト 11 | > 12 | > - [x] React のコンポーネントの概念を理解する 13 | > - [x] React の State とライフサイクルについて理解する 14 | > - [x] React のデザインスシテムについて理解する 15 | > - [x] Youtube アプリの構築に必要なコンポーネントの設計 16 | > - [x] 必要ライブラリーのインストール 17 | > - [x] デザインの前に、ルーティングを作成 18 | > - [x] Header のデザインを作成 19 | > - [x] Sidebar のデザイン作成 20 | > - [x] ビデオカードのデザイン作成 21 | > - [x] 動画再生画面のデザイン作成 22 | > - [x] 動画アップロード画面のデザイン作成 23 | 24 |
25 | 26 | ## 次回までの目標 27 | 28 | - [ ] インフラを構築して、ユーザーの認証とデータの保存ができるようにしよう 29 | 30 | ## 今週のやることリスト 31 | 32 | - [ ] Bootcamp のインフラアーキテクチャ 33 | - [ ] Firebase Authentication について 34 | - [ ] Firebase Storage について 35 | - [ ] Hasura について 36 | - [ ] GraphQL について 37 | - [ ] Firebase の設定 38 | - [ ] React で Firebase を呼び出す 39 | - [ ] React で認証を実装 40 | - [ ] React でアップローダーを実装 41 | - [ ] Hasura の設定 42 | - [ ] データベースの設計 43 | - [ ] Hsaura でデータを作成する 44 | - [ ] React で GraphQL 45 | - [ ] GraphQL Code Generator で爆速開発 46 | - [ ] JWT トークンで GraphQL をセキュアに 47 | 48 | ### 目次 49 | 50 | - [Bootcamp のインフラアーキテクチャ](#bootcamp-のインフラアーキテクチャ) 51 | - [構成理由 1:開発工数の削減](#開発工数の削減) 52 | - [構成理由 2:なるべく本番環境に近い構成](#なるべく本番環境に近い構成) 53 | - [構成理由 3:枯れた技術を踏襲しつつ、トレンドにもノッていく](#枯れた技術を踏襲しつつトレンドにもノッていく) 54 | - [Firebase について](#firebase-について) 55 | - [Firebase により提供されるサービス](#firebase-により提供されるサービス) 56 | - [どのくらい便利なのか](#どのくらい便利なのか) 57 | - [驚異の無料枠](#驚異の無料枠) 58 | - [Hasura について](#hasura-について) 59 | - [GraphQL について](#graphQL-について) 60 | - [GraphQL と RESTfull API](#graphql-と-restfull-api) 61 | - [GraphQL のメリット](#graphql-のメリット) 62 | - [そんな GraphQL を簡単に構築できるのが Hasura です](#そんな-graphql-を簡単に構築できるのが-hasura-です) 63 | - [Hasura のメリット](#hasura-のメリット) 64 | - [GraphQL について](#graphql-について) 65 | - [Firebase の設定](#firebase-の設定) 66 | - [React で Firebase を呼び出す](#react-で-firebase-を呼び出す) 67 | - [firebase パッケージのインストール](#firebase-パッケージのインストール) 68 | - [firebase API Key の設定](#firebase-api-key-の設定) 69 | - [React で認証を実装](#react-で認証を実装) 70 | - [React でアップローダーを実装](#react-でアップローダーを実装) 71 | - [Hasura の設定](#hasura-の設定) 72 | - [データベースの設計](#データベースの設計) 73 | - [必要なデータの洗い出し](#必要なデータの洗い出し) 74 | - [データのリレーションを設計](#データのリレーションを設計) 75 | - [データの正規化](#データの正規化) 76 | - [Hsaura でデータを作成する](#Hsaura-でデータを作成する) 77 | - [React で GraphQL](#react-で-graphql) 78 | - [GraphQL Code Generator で爆速開発](#graphql-code-generator-で爆速開発) 79 | - [GraphQL Code Generator](#graphql-code-generator) 80 | - [Apollo Client](#apollo-client) 81 | 82 | # ReactBootcamp 第三回目勉強会ドキュメント 83 | 84 | 第三回目は、React から少し離れて、インフラ周りを重点的に構築して、アプリケーションのバックエンド側の構築をしていきます。 85 | 86 | とはいえ、サーバーレスなアプリケーション構築を目指していくので、基本的にバックエンド側のコードを書くことはありません。 87 | 88 | 様々なサービスをうまく使って、工数の少ないアプリケーション開発を目指していきます。 89 | 90 | わからないこと、疑問点、ドキュメントやソースコードの間違いなどは下記 Discord にてメッセージお願いします。 91 | 92 | [React Bootcamp Discord](https://discord.gg/rCAVXFvEPJ) 93 | 94 | ## Bootcamp のインフラアーキテクチャ 95 | 96 | [第一回目勉強会](https://youtu.be/BzPGDSeJfdM)でもご説明した通り、Bootcamp アプリケーションのインフラは下記のようなサービスを用いて構築していきます。 97 | 98 | - Firebase : BaaS 99 | - Authentication : ユーザー認証 100 | - Storage : 動画の保存場所 101 | - Hasura : サーバーレスな GraphQL サーバー 102 | - GraphQL : API のスキーマ 103 | - Heroku : PaaS 104 | - PostgreSQL : データベースの実態 105 | 106 | ![bootcamp infra list](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/bootcamp_infra_list.jpg?raw=true) 107 | 108 | それぞれのクラウドは以下のようなアーキテクチャで関連しています。 109 | 110 | ![bootcamp infra architecture](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/bootcamp_infra_architecture.jpg?raw=true) 111 | 112 | データの保存場所としての Hasura と Heroku、ユーザーの認証のための Firebase Authentication、動画を保存する外部レージとしての Firebase Storage と言う形で、それぞれを必要に応じて呼び出し分ける形にしています。 113 | 114 | 今回、このような構成にした理由が 3 つあります。 115 | 116 | 1. 開発工数の削減 117 | 2. なるべく本番環境に近い構成 118 | 3. 枯れた技術を踏襲しつつ、トレンドにもノッていく 119 | 120 | - ### 開発工数の削減 121 | 122 | 今回は、React での開発に集中したいので、バックエンド側の構築は全てサーバーレスな設計で組みました。 123 | 124 | 特に個人開発の場合は、リソース(時間とお金)が限られているので、最低限の時間で構築できるかつ、Free プランが充実している構成で構築しました。 125 | 126 | 今回取り上げたサービスは全て Web コンソールが用意されております。 127 | 128 | そのため、ターミナルを開いてコマンドを打ったり、ソースコードを書いて環境構築をしたりと言った煩わしい作業から全て開放されます。 129 | 130 | それぞれのサービスを使うときは、ブラウザ上でポチポチ設定を選択するだけで、本番環境の構築まで完了します。 131 | 132 | これらのサービスを使うことで、もちろん開発のコードを書くスピードも上がりますが、それ以上にインフラ周りの基盤が安定させることができます。 133 | 134 | 特にセキュリティやスケーリングなどの問題は、それだけで専門のエンジニアが必要なほど深く重い領域です。 135 | 136 | それらのことを考えなくても、ある程度のセキュリティを担保されることはエンジニアとしては非常にありがたいですね。 137 | 138 | - ### なるべく本番環境に近い構成 139 | 140 | 今回は、エッジケースでの環境構築をなるべく避けました。 141 | 142 | どう言うことかというと、React での開発でよく見かけるインフラのアーキテクチャでは全て Firebase で構築する構成が見受けられます。 143 | 144 | 今回で言うと、Hasura を用いている箇所が Firebase に置き換えらている構成です。 145 | 146 | しかし、Firebase でのデータベース管理では、`NoSQL`と言う`RDB`ではないデータベースの選択肢しかありません。 147 | 148 | これの何がいけないかというと、ほとんどの企業では`RDB`を用いたデータベース管理をしているのにも関わらず、「`NoSQL`でアプリを構築できます!」では通用しないということです。 149 | 150 | もちろん`NoSQL`を用いてプロダクトを開発している企業はたくさんありますが、それでもその企業の一体どれほどが Firebase を用いているのでしょうか? 151 | 152 | このように、Firebase を用いたデータベース管理では、Firebase でのみのデータベースの管理の仕方しか学ぶことができません。 153 | 154 | そのため、今回は特定のサービスになるべく依存せずに、広く使われている技術を用いてインフラを整備していきます。 155 | 156 | > それでも、サーバーレスな構成を選ぶ以上、何かしらのサービスに依存した環境になってしまいます。 157 | > それぞれのサービスを選ぶ上で、変更容易性がどれほどあるかを考えながら構築することが必要です。 158 | 159 | - ### 枯れた技術を踏襲しつつトレンドにもノッていく 160 | 161 | 今回の構成で一番のポイント GraphQL を用いた構成になっていることではないでしょうか。 162 | 163 | GraphQL はここ数年でたくさんの運用事例が生まれ、`Github`や`Airbnb`、`Netflix`などの巨大企業が GraphQL での開発を進めています。 164 | 165 | もう既に GraphQL は、革新的な技術からスタンダードな技術へと変貌を遂げつつあります。 166 | 167 | とは言え、まだまだ「枯れた技術」の域まではいっていなく、今後も「トレンディングな技術」としてたくさんの導入事例が生まれてくる技術であると思っています。 168 | 169 | GraphQL の裏では、昔ながらの RDB である`PostgreSQL`を採用し、完全に「枯れた技術」も採用しています。 170 | 171 | 全てを新しいトレンディングな技術にするのではなく、枯れた技術も使いながら今の時代に生きるエンジニアとしての力をつけれればと思います。 172 | 173 | ## Firebase について 174 | 175 | 早速、今回使用するインフラのサービスを説明していきます。 176 | 177 | それぞれの説明が不要な場合は、[Firebase の設定](#firebase-の設定)から実際の環境の構築を行なっていってください。 178 | 179 | - ### Firebase とは 180 | 181 | > Google「君らサービス開発する時、毎回似たようなもの用意したり作るでしょ?それもうやっといたから。まとめて Firebase って呼ぶわ。」 182 | > Google「サーバを持ってない?必要ならマシン貸すよ。もしサーバを管理したくないならソースコードだけくれたらそれで勝手にホスティングしてオートスケールするよ」 183 | > Google「お金?個人の趣味範囲なら要らんよ」 184 | > 185 | > 引用:[わかる!Firebase ~全てのサービスをおつまみ紹介~](https://qiita.com/dogwood008/items/fa95b62ad151f823af70) 186 | 187 | Firebase とは、Google が提供するアプリケーションのバックエンド処理を一手に引き受けてくれる Cloud サービスです。 188 | 189 | アプリケーション開発で必要になってくるバックエンドの処理を全て一つのプラットフォーム上に統合することで、開発者はバックエンドの処理を意識することなくフロントの開発に専念できるようになります。 190 | 191 | いわゆる「サーバーレス」と呼ばれるアーキテクチャであり、「Baas」という名前のサービスです。 192 | 193 | - ### Firebase により提供されるサービス 194 | 195 | Firebase にはたくさんのバックエンド処理が用意されています。 196 | 197 | - [Authentication](https://firebase.google.com/docs/auth?authuser=0) : 認証サービス 198 | - メールでログインしたり、Google でログインしたり、Github でログインしたりできる 199 | - [Cloud Firestore](https://firebase.google.com/docs/firestore?authuser=0) : NoSQL ライクな firebase 専用のデータベース 200 | - いわゆるデータベースでできることは大体できる 201 | - [Cloud Storage](https://firebase.google.com/docs/storage?authuser=0) : ストレージ、ファイルの保存ができる 202 | - 低コストのファイル置き場。 203 | - [Hosting](https://firebase.google.com/docs/hosting?authuser=0) : 静的ファイルのホスティング、主に HTML や JS をホスティングする 204 | - Web ページのホスティングが可能。もちろん React のアプリもホスティング可能 205 | - [Cloud Functions](https://firebase.google.com/docs/functions?authuser=0) : サーバーレスでサーバー処理を実行する 206 | - AWS でいうところの Lambda。Node.js で処理を書いてデプロイするだけでバックエンド処理が完成 207 | 208 | 上記以外にも本当にたくさんの機能群が用意されております。 209 | 210 | 他の機能を確認したい人は[こちら](https://firebase.google.com/docs?authuser=0)から確認できます。 211 | 212 | - ### どのくらい便利なのか 213 | 214 | この Firebase、例えば React にログイン機能を実装したい場合、たったの 3 ステップでアプリケーションにログインの機能をつけるとことができます。 215 | 216 | > Firebase セットアップの詳細は[Firebase の設定](#firebase-の設定)をご覧ください。 217 | 218 | 1. Firebase のセットアップ 219 | 220 | [firebase のコンソール](https://console.firebase.google.com/u/0/)にアクセスして、ご自身の Google アカウントでログインするだけでプロジェクトの作成が可能になります。 221 | 222 | ![step1 firebase setup](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/step1_firebase_setup.png?raw=true) 223 | 224 | 2. Firebase API キーの取得 225 | 226 | プロジェクトの作成が完了した後に、この Firebase プロジェクトにアクセスするための API キーを取得する事ができます。 227 | 228 | ![step2 firebase API Key](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/step2_firebase_api_key.png?raw=true) 229 | 230 | 3. React で Firebase を呼び出す。 231 | 232 | API キーを React で読み込み、`firebase`のライブラリを使用するだけで、もうログインの機能が実装完了しました。 233 | 234 | ![step3 firebase login](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/step3_firebase_login.png?raw=true) 235 | 236 | たったのこの 3 ステップでアプリケーションにログイン機能を実装することができました。 237 | 238 | この恐ろしいほど早い実装が Firebase の威力です。 239 | 240 | ただ単純に機能を実装するためには、これだけの簡単さで実装することができます。 241 | 242 | 今回の Bootcamp ではここから少し踏み込んで、エラー処理やリダイレクト機能を組み込むことで、より使いやすいプロダクトにしていきます。 243 | 244 | - ### 驚異の無料枠 245 | 246 | もう一つ、Firebase を語る上で、外せないのがその無料枠の規模です。 247 | 248 | 大抵、クラウド系のサービスは無料枠が設けられていることがほとんどですが、その中でも Firebase は群を抜いて無料枠が充実しています。 249 | 250 | [Firebase の料金表](https://firebase.google.com/pricing?hl=ja) 251 | 252 | ![firebase pricing](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_pricing.png?raw=true) 253 | 254 | 例えば、今回の認証について、1 ヶ月間に 1 万回の認証までは無料で運用する事ができます。 255 | 256 | そして、課金が必要なトラクションになったとしても、1 認証あたり 6 円と急に課金が跳ね上がるといった心配もありません。 257 | 258 | ここでも、Google 帝国のパワーは健在です。 259 | 260 | ## Hasura について 261 | 262 | Hasura とは、GraphQL サーバーを簡単に構築するサービスです。 263 | 264 | Hasura の説明の前に、GraphQL の説明を先にしたほうが理解が早いかもしれません。 265 | 266 | - ### GraphQL について 267 | 268 | GraphQL とは、Facebook が開発している Web API のための規格です。 269 | 270 | その実態は、「クエリ言語」と「スキーマ言語」からなります。 271 | 272 | 技術詳細の前に、GraphQL と RESTfull API との比較を行うことでその概観を把握していきます。 273 | 274 | - ### GraphQL と RESTfull API 275 | 276 | 今までの WEB 開発では、フロントエンドとバックエンドの橋渡しとして REST API を用いた方法でデータのやり取りをしていました。 277 | 278 | 例えば、`user`データをバックエンドから取得しようとすると、`/user`という API のエンドポイントに`Request`を送信することで、`user`データを取得していました。 279 | 280 | ![RESTfull api architecture](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/restfull_api_architecture.png?raw=true) 281 | 282 | 上記であれば、エンドポイントが`user`と`video`の 2 つなのでまたシンプルです。 283 | 284 | これが、10 個、50 個とエンドポイントが増えていった場合どうなるでしょうか。 285 | 286 | 開発も運用もかなり複雑になることが想像できるかと思います。 287 | 288 | では、反対に GraphQL の場合、どうなるか見ていきましょう。 289 | 290 | ![GraphQL architecture](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/graphql_api_architecture.png?raw=true) 291 | 292 | GraphQL ではエンドポイントがただ一つのみ提供されます。 293 | 294 | クライアントからは、この唯一提供されるエンドポイントに対して`Request`を送るのみでデータを取得できます。 295 | 296 | - ### GraphQL のメリット 297 | 298 | GraphQL 最大のメリットは、データの型がしっかり定義されているので、クライアントとサーバー間の食い違いが減少します。 299 | 300 | 例えば、`User`というデータを取る時、クライアントでもサーバーでも同じ`User`の型を参照する事ができます。 301 | 302 | RESTful API での`user`取得 303 | 304 | ![rest fetch user](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/rest_fetch_user.png?raw=true) 305 | 306 | GraphQL API での`user`取得 307 | 308 | ![graphql fetch user](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/graphql_fetch_user.png?raw=true) 309 | 310 | [GraphQL について](#graphql-について)で`「その実態は、「クエリ言語」と「スキーマ言語」からなります。」`と説明しました。 311 | 312 | この「クエリ」と「スキーマ」というものをクライアントとサーバーで共有することで、全く同じデータソースのもとデータのやり取りを行うことができます。 313 | 314 | クライアントは、どの「クエリ」と「スキーマ」を指定して取得するかに注意すればよく、そのデータを実際にどのように取得するかは GraphQL サーバーに全て一任することができます。 315 | 316 | また、サーバーは「クエリ」と「スキーマ」のルールに則ってさえいれば、データを実際にどのように取得するかは開発者に任せられます。 317 | 318 | GraphQL では「クエリ」と「スキーマ」が唯一信頼できるデータソースとしてクライアントとサーバーに秩序をもたらします。 319 | 320 | また、GraphQL は「秩序ある神エンドポイント`/graphql`」API を提供します。 321 | 322 | GraphQL は、RESTful API のようにデータソースごとに無限にエンドポイントを生やすということをすることなく、ただ唯一信頼できる「エンドポイント」と「データソース」を提供します。 323 | 324 | 他にもたくさんの RESTful API にはないメリットが存在します。 325 | 326 | そちらに関しては、ネットの記事のほうが詳しく記載されているので、気になる方は下記をご確認ください。 327 | 328 | [アプリ開発の流れを変える「GraphQL」は REST とどう違うのか比較してみた](https://www.webprofessional.jp/rest-2-0-graphql/) 329 | 330 | [REST と比較 GraphQL について調べてみた。](https://www.slideshare.net/atsu666/rest-graphql-75297436) 331 | 332 | - ### そんな GraphQL を簡単に構築できるのが Hasura です 333 | 334 | 上記までで、GraphQL を導入するメリットをご理解いただけたと思います。 335 | 336 | そんな便利な GraphQL ですが、GraphQL 自体はあくまで「規格」です。 337 | 338 | なので、GraphQL が実装されたサーバーを用意しないと、GraphQL を使用することはできません。 339 | 340 | GraphQL サーバーの構築に必要なのは、「GraphQL のエンドポイントの作成」「データベースの構築」「クエリやスキーマの実際のデータベースへの処理」「エラー処理」などなどが必要になります。 341 | 342 | お気づきの方もおられるかもしれませんが、「GraphQL」は決してバックエンド処理を「書かなくて良い」銀の弾丸なのではなく、あくまでバックエンドとフロントエンドの開発のエクスペリエンスを高めるものでしかありません。 343 | 344 | そんな GraphQL を「銀の弾丸」に進化させるサービスが今回使用する Hasura です。 345 | 346 | 初めに Hasura の説明で`「GraphQL サーバーを簡単に構築するサービスです。」`とご説明しました。 347 | 348 | そうです、Hasura はこの便利な GraphQL を簡単に構築する事ができるサービスです。 349 | 350 | GraphQL を本当に意味で、バックエンド処理を書かなくて良い銀の弾丸にしてくれるサービスなのです。 351 | 352 | - ### Hasura のメリット 353 | 354 | Hasura は、簡単に GraphQL サーバーを構築できるサービスなのですが、その中でも嬉しい機能がたくさん用意されています。 355 | 356 | 1. Web だけで完結 357 | 358 | Hasura には Web コンソールが用意されています。 359 | 360 | これにより、ブラウザ上で全ての操作が可能になっています。 361 | 362 | 2. データベースの管理までしてくれる 363 | 364 | GraphQL は、あくまでデータフェッチ用のプロキシサーバーでしかなく、データベースの管理は別途必要になります。 365 | 366 | Hasura であれば、このデータベースの管理まで自動化してくれています。 367 | 368 | Web コンソール上でポチポチするだけで、データベースの構築からテーブルの操作、カラムの管理まで全て Hasura 内で完結させることも可能です。 369 | 370 | 3. 無料枠がある 371 | 372 | Hasura にも無料枠が存在する 373 | 374 | 無料の条件は「1 分間に 60 リクエストまで」です。 375 | 376 | Firebase と比べると、本番環境でユーザーに触ってもらい初めたらすぐに有料プランへのアップデートが必要そうな条件です。 377 | 378 | しかし、それまでのテスト段階の開発では、プロダクトをテストしながら実際に動作させる分には十分な枠が用意されています。 379 | 380 | 4. もとはオープンソースなので、Hasura のエコシステムは Github に 381 | 382 | じつは、Hasura はオープンソースとして提供されているので、Web コンソール経由ではなく、[Hasura Engine](https://github.com/hasura/graphql-engine)で自身で Hsaura を構築することも可能です。 383 | 384 | そのため、Hsaura のバグや質問は Github に集約されており、普通のクラウドサービスよりバグ FIX がしやすくなっています。 385 | 386 | 5. データベースレベルでのセキュリティ 387 | 388 | Hasura はパーミッション設定もコンソール上で簡単に構築できます。 389 | 390 | フロントエンドエンジニアは SQL を操作することに慣れていない事が多いので、SQL を触らずにデータベースの設定ができることは大変嬉しいですね。 391 | 392 | ## Firebase の設定 393 | 394 | では早速、Firebase の設定に入っていきたいと思います。 395 | 396 | と言いつつも Firebase は説明が不要なほど簡単にプロジェクトの作成が可能です。 397 | 398 | 手順通りに進めて、Firebase のプロジェクトを作成していきましょう。 399 | 400 | まずは、Firebase のコンソールにアクセスしみましょう。 401 | 402 | もし初めてアクセスされる方は、ログイン画面が表示されるので、ご自身の Google アカウントでログインしてください。 403 | 404 | [Firebase コンソール](https://console.firebase.google.com/u/1/) 405 | 406 | ![google login](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/google_login.png?raw=true) 407 | 408 | ![firebase console](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_console.png?raw=true) 409 | 410 | 「プロジェクトの作成」から作成を開始ましょう。 411 | 412 | ![firebase create project name](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_create_project_name.png?raw=true) 413 | 414 | プロジェクト名に適当な名前を入力して、規約に同意するをチェックして、「続行」を押します。 415 | 416 | 次の画面は、アプリケーションに Google アナリティクスの設定になります。 417 | 418 | アプリケーションを運用していく上では必須の機能ですが、今回はデモアプリということで設定ぜずに進めて言います。 419 | 420 | もちろん設定して頂いても構いません。 421 | 422 | ![firebase create analytics](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_create_analytics.png?raw=true) 423 | 424 | 続行でプロジェクトの作成が開始します。 425 | 426 | ![firebase create pendeing](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_create_pendeing.png?raw=true) 427 | 428 | 新しいプロジェクトの準備が完了したら、「続行」で Firebase プロジェクトのコンソールが出来上がります。 429 | 430 | ![firebase project console](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_project_console.png?raw=true) 431 | 432 | ここまでで、Firebase の設定が完了しました。 433 | 434 | 次にやることは、Web アプリケーション用の「アプリ」を作成していくことです。 435 | 436 | Firebase には、Web 以外にも Andorid や iOS からもデータベースなどの機能が使えるようになっています。 437 | 438 | そのため、それぞれのプラットフォーム用に「アプリ」を作成して、プラットフォーム用の`API Key`を作成する必要があります。 439 | 440 | 今回は Web のみの使用なので、Web 用の「アプリ」を作成していきます。 441 | 442 | プロジェクトコンソールの歯車マークから「プロジェクトを設定」を選択します。 443 | 444 | ![firebase config](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_config.png?raw=true) 445 | 446 | プロジェクトの様々な情報が表示されたページが表示され、そのページの下部に「アプリ」作成用の場所が用意されています。 447 | 448 | ![firebase config web app](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_config_web_app.png?raw=true) 449 | 450 | まだ「アプリ」が作成されていないので、アプリを作成していきましょう。 451 | 452 | 「iOS」「Android」「Web」| 「Unity」の順番でそれぞれのプラットフォーム用の「アプリ」作成ボタンが用意されています。 453 | 454 | 今回は「Web」の``というボタンを選択します。 455 | 456 | そうすると「アプリ」作成画面が表示されます。 457 | 458 | 先ほどと同じように適当な名前を入力して「アプリを登録」でアプリを作成します。 459 | 460 | ※Firebase Hosting はいつでも作成できるので今は選択しなくても大丈夫です。 461 | 462 | ![firebase web create](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_web_create.png?raw=true) 463 | 464 | アプリの登録が完了すると、「Firebase SDK の追加」という項目が表示されます。 465 | 466 | ここに表示されている情報が、React から Firebase を呼び出すために必要な情報になっています。 467 | 468 | 後からいつでも確認できるので、一旦「コンソールに進む」でコンソールに戻りましょう。 469 | 470 | コンソールに戻ると「SDK の設定と構成」に先ほどと同じ情報が記載されています。 471 | 472 | ![firebase config api key](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_config_api_key.png?raw=true) 473 | 474 | 「プロジェクトの設定」>「SDK の設定と構成」から SDK 用の API Key などの情報をいつでも確認できます。 475 | 476 | ここまでで Firebase のセットアップが完了しました。 477 | 478 | 次から実際に React のアプリケーションに Firbase を追加していきたいと思います。 479 | 480 | ## React で Firebase を呼び出す 481 | 482 | React から Firebase を呼び出すためには二つの準備が必要です。 483 | 484 | 1. firebase パッケージのインストール 485 | 2. API Key の設定 486 | 487 | まずは、firebase のパッケージのインストールから初めていきます。 488 | 489 | - ### firebase パッケージのインストール 490 | 491 | firebase パッケージのインストールは`Material-UI`をインストールした時と全く同じ要領でインストールできます。 492 | 493 | ```bash 494 | npm install firebase@8.10.0 495 | ``` 496 | 497 | 以上です! 498 | 499 | - ### firebase API Key の設定 500 | 501 | 続いて、Firebase の API Key を React に設定していきます。 502 | 503 | API Key は先ほどの Firebase コンソールの「プロジェクトの設定」>「SDK の設定と構成」から取得していきます。 504 | 505 | まずは、firebase のセットアップ処理 React のアプリケーションに作成していきます。 506 | 507 | React プロジェクトに以下のファイルを作成して処理を書いてください。 508 | 509 | ```TS 510 | // src/utils/Firebase/config.tsを作成 511 | 512 | // Firebase コンソールの「プロジェクトの設定」>「SDK の設定と構成」から「構成」を選択し、そのままコピペ 513 | const firebaseConfig = { 514 | apiKey: "AIzaSyCm8ZVPFvB4O5YVyNqA-16zWrRpbxd0RVQ", 515 | authDomain: "react-bootcamp-78947.firebaseapp.com", 516 | projectId: "react-bootcamp-78947", 517 | storageBucket: "react-bootcamp-78947.appspot.com", 518 | messagingSenderId: "236750478038", 519 | appId: "1:236750478038:web:fc2e6a6e2f856cae1c4777", 520 | }; 521 | ``` 522 | 523 | この API Key を React で読み込んで firebase を React で初期化します。 524 | 525 | ```TS 526 | // src/utils/Firebase/config.ts 527 | 528 | import firebase from "firebase"; 529 | 530 | const firebaseConfig = { 531 | apiKey: "AIzaSyCm8ZVPFvB4O5YVyNqA-16zWrRpbxd0RVQ", 532 | authDomain: "react-bootcamp-78947.firebaseapp.com", 533 | projectId: "react-bootcamp-78947", 534 | storageBucket: "react-bootcamp-78947.appspot.com", 535 | messagingSenderId: "236750478038", 536 | appId: "1:236750478038:web:fc2e6a6e2f856cae1c4777", 537 | }; 538 | 539 | // firebaseパッケージをAPI Keyで初期化 540 | // Firebaseコンソールでさksウエイ他アプリとReactを紐づける処理 541 | firebase.initializeApp(firebaseConfig); 542 | 543 | // 認証用のfirebaseモジュール 544 | export const fireAuth = firebase.auth(); 545 | 546 | // ストレージ用のfirebaseモジュール 547 | export const storage = firebase.storage(); 548 | 549 | // 初期化済みのfirebaseパッケージを確実に使用するためのexport defaultでfirebaseパッケージをexport 550 | export default firebase; 551 | ``` 552 | 553 | ここまでで、React で firebase を使用する準備ができました。 554 | 555 | と、ここで、「API Key をハードコーディングしていいのか!?」と思われた方がいるかもしれません。 556 | 557 | 結論から言うと、「大丈夫」です。 558 | 559 | 理由として、Google がこの Firebase の構成を public な状態で運用することを前提として設計しているからです。 560 | 561 | それが垣間見えるのが、Firebase の環境構成の Google のドキュメントです。 562 | 563 | ![firebase public env](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_public_env.png?raw=true) 564 | 565 | これは HTML から CDN を通して Firebase を使用する構成例です。 566 | 567 | 天下の Google 様がドキュメントで公開したらまずい構成を公開で設定するよう指示するでしょうか? 568 | 569 | いや、しない! 570 | 571 | と言うことで、もう少し詳しく説明すると、Firebase では「パーミッション」を設定することで、どのようなユーザーが Firebase のリソースにアクセスするかを制限することができます。 572 | 573 | なので、仮に第三者が API Key を使用しても、許可されていなければリソースにアクセスすることができません。 574 | 575 | とは言え、例えば、アカウントの新規作成をされてしまえば、そのアカウントの範囲内であればリソースへのアクセスがされてしまいます。 576 | 577 | そういったことを制限するための方法も、Firebase では用意されています。 578 | 579 | 詳しくはこちらの「[Firebase の API キーは公開しても大丈夫だよ](https://shiodaifuku.io/articles/txEgArhm4Z2BOzrd0IKJ#%E3%82%82%E3%81%86%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E5%AE%89%E5%85%A8%E3%82%92%E7%A2%BA%E4%BF%9D%E3%81%97%E3%81%9F%E3%81%84%E4%BA%BA%E5%90%91%E3%81%91%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84)」をご確認ください。 580 | 581 | そもそも、アプリケーションをパブリックにデプロイしている時点で、どのような形であれ「全ての通信やリソースへのアクセスは可能」です。 582 | 583 | そんな中で、API Key を「見えない」ように隠したぐらいでセキュリティが確保されたと思うなよ、と言うことですね。 584 | 585 | 本当にセキュリティを確保したい場合は、「そもそもバレても大丈夫だよね」と言う構成にして、バレてもリソースにアクセスされない構成にすることが大事です。 586 | 587 | > とはいえ全てのサービスがそのような構成にしているわけでは無いので、ドキュメントをよく読み、公開しても大丈夫な情報かを確認する必要があります。 588 | 589 | ## React で認証を実装 590 | 591 | React で認証機能を使う前に、Firebase で認証機能を使えるように設定しなければなりません。 592 | 593 | また、Firebase のプロジェクトコンソールから「Authentication」のコンソールに移動します。 594 | 595 | 「構築」>「Authentication」 596 | 597 | ![firebase authentication](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_authentication.png?raw=true) 598 | 599 | 「始める」を押すとログインに使用するプロバイダーを選択する画面になります。 600 | 601 | このプロバイダとは、例えばアプリケーション内に Google によるログインや、Github ログインができるようにするための設定です。 602 | 603 | 一覧に載っているプロバイダであれば、認証に使用することができます。 604 | 605 | とりあえず今回は、メールアドレスによる認証ができるようにします。 606 | 607 | 「メール/パスワード」の横にあるペンマークを押して、メールアドレス認証を有効にします。 608 | 609 | ![enable email auth](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/enable_email_auth.png?raw=true) 610 | 611 | 保存を押すとメールアドレスによる認証を有効にします。 612 | 613 | これで React からメールアドレス認証ができるようになりました。 614 | 615 | では早速、ログイン、サインアップ、ログアウトなどの機能を実装していきましょう。 616 | 617 | ここでは、ログインなどのコアの機能を実装し、実際にユーザーからの入力に合わせてログインするといったことは、次週以降実装していきます。 618 | 619 | まずはログイン機能から実装していきます。 620 | 621 | Firebase の処理は、後から、Firebase 以外のログイン機能に移行するという可能性を考えて、アプリケーションのロジックから一歩離れた位置で実装します。 622 | 623 | この実装にすることで、アプリケーションのロジック側から「何か知らんけど、メールアドレスとパスワードを渡すと認証が終わる」といった状態にします。 624 | 625 | → つまり、アプリケーションのロジックから Firebase の処理を隠しています。 626 | 627 | ```TS 628 | // src/utils/Firebase/login.tsを作成 629 | // loginのコード 630 | 631 | // firebaseのauthをimport 632 | import { fireAuth } from "./config"; 633 | 634 | // ログインに必要な引数の型を定義しています。 635 | // login()関数では、引数にFireLoginTypeの型、つまり文字型の`email`と`password`が必要になります。 636 | export type FireLoginType = { 637 | email: string; 638 | password: string; 639 | }; 640 | 641 | /** 642 | * ログイン処理の実態です。 643 | * firebaseのログイン処理をラップしているだけです。 644 | * @param {email, password} ログインに必要な値 645 | * @returns Promise 646 | */ 647 | export const login = ({ email, password }: FireLoginType) => 648 | fireAuth.signInWithEmailAndPassword(email, password); 649 | 650 | 651 | ``` 652 | 653 | 以上で、ログインの実態は完成しました。 654 | 655 | あとはロジック側からこの処理を呼び出すだけで、全てのログイン処理が完了します。 656 | 657 | ロジックからは、firebase の初期化や呼び出しを意識することなくログイン処理を実行できます。 658 | 659 | 合わせて、サインアップ処理とログアウト処理を書いていきましょう。 660 | 661 | ```TS 662 | // src/utils/Firebase/signup.tsを作成 663 | // signupのコード 664 | 665 | // firebaseのauthをimport 666 | import { fireAuth } from "./config"; 667 | 668 | // サインアップに必要な引数の型を定義しています。 669 | // signup()関数では、引数にFireSignupTypeの型、つまり文字型の`email`と`password`が必要になります。 670 | export type FireSignupType = { 671 | email: string; 672 | password: string; 673 | }; 674 | 675 | /** 676 | * サインアップ処理の実態です。 677 | * firebaseのサインアップ処理をラップしているだけです。 678 | * @param {email, password} ログインに必要な値 679 | * @returns Promise 680 | */ 681 | export const signup = ({ email, password }: FireSignupType) => 682 | fireAuth.createUserWithEmailAndPassword(email, password); 683 | 684 | ``` 685 | 686 | 続いて、ログアウトです。 687 | 688 | ```TS 689 | // src/utils/Firebase/signout.tsを作成 690 | // signoutのコード 691 | 692 | import { fireAuth } from "./config"; 693 | 694 | export const signout = () => fireAuth.signOut(); 695 | ``` 696 | 697 | ログアウトはさらにシンプルな実装になっていますね。 698 | 699 | 一つ処理を忘れていました。 700 | 701 | ユーザーがパスワードを忘れた場合にパスワードをリセットする用のメールを送信する処理です。 702 | 703 | ```TS 704 | // src/utils/Firebase/forgetPass.tsを作成 705 | // forgetPassのコード 706 | 707 | import { fireAuth } from "./config"; 708 | 709 | /** 710 | * パスワードリセット用のメールを送信する関数 711 | * @param email メールアドレス 712 | * @returns 713 | */ 714 | export const forgetPass = (email: string) => 715 | fireAuth.sendPasswordResetEmail(email); 716 | ``` 717 | 718 | ここまでで、認証に必要な全てのコア処理の実装が完了しました。 719 | 720 | あとは、アプリケーションのロジックからこれらの処理を呼び出し、成功時の処理や失敗時のエラーハンドリングを行うことで、認証機能が完成します。 721 | 722 | 具体的なロジック処理は次週以降実装していきます。 723 | 724 | ## React でアップローダーを実装 725 | 726 | 続いて、Firebase のストレージを設定していきます。 727 | 728 | Authentication と同じように設定していきます。 729 | 730 | 「Firebase コンソール」>「構築」>「Storage」からストレージの設定を行います。 731 | 732 | ![firebase config storage](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_config_storage.png?raw=true) 733 | 734 | 「始める」を押すと、設定が開始されます。 735 | 736 | まず初めに出てくる設定項目はストレージのセキュリティについてです。 737 | 738 | これは、ストレージのリソースにどのようなユーザーユーザーはアクセスできるかのルールを設定します。 739 | 740 | デフォルトでは、認証されたユーザーがストレージへのアップロードとダウンロードが許可されています。 741 | 742 | 今は設定できないのでまた後ほど設定します。 743 | 744 | 「次へ」で次に進みます。 745 | 746 | ![firebase config storage rule](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_config_storage_rule.png?raw=true) 747 | 748 | 次の設定は、リージョンの設定です。 749 | 750 | これは、世界中に存在するサーバーのどこを使用するかを設定します。 751 | 752 | 処理時間い影響が出てくるので、なるべくユーザーの近いところに置くことをお勧めします。 753 | 754 | - asia-northeast1 : 東京 755 | - asia-northeast2 : 大阪 756 | 757 | [その他のリージョン情報](https://firebase.google.com/docs/firestore/locations?hl=ja) 758 | 759 | 今回は東京(asia-northeast1)を選択します。 760 | 761 | ![firebase storage region](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_storage_region.png?raw=true) 762 | 763 | 「完了」でストレージの構築が開始されます。 764 | 765 | 終了するとストレージのコンソールが表示されます。 766 | 767 | ここに全てのファイルリソースをを格納していきます。 768 | 769 | ![firebase storage console](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_storage_console.png?raw=true) 770 | 771 | 先に、ストレージのセキュリティを設定しておきましょう。 772 | 773 | コンソールの上部に「Rules」という項目があるので、ここからルールを設定していきます。 774 | 775 | ![firebase storage rurles](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_storage_rurles.png?raw=true) 776 | 777 | 初めに説明した通り、デフォルトでは認証されたユーザーのみがファイルのアップロードを許可されています。 778 | 779 | 今回のアプリケーションでユーザーがアップロードするファイルは以下の通りです。 780 | 781 | ``` 782 | . 783 | ├── videos 784 | │   └── [videoId].mp4 785 | └── thumbnails 786 |    └── [thumbnailId].png 787 | ``` 788 | 789 | ユーザーは、動画のアップロード/ダウンロードとサムネイル画像のアップロード/ダウンロードができます。 790 | 791 | しかし、ここで、「アップロード」処理はログイン済みのユーザーだけに限定したいです。 792 | 793 | そこで、ログイン済みのユーザーには、アップロード/ダウンロードを許可し、ログインしていないユーザーにはダウンロードのみを許可したいです。 794 | 795 | この条件を Firebase Storage に反映していきます。 796 | 797 | 結論だけ記載すると以下のようなルールにします。 798 | 799 | ``` 800 | rules_version = '2'; 801 | service firebase.storage { 802 | match /b/{bucket}/o { 803 | match /videos/{allPaths=**} { 804 | allow read; 805 | allow write: if request.auth != null 806 | } 807 | 808 | match /thumbnails/{allPaths=**} { 809 | allow read; 810 | allow write: if request.auth != null 811 | } 812 | } 813 | } 814 | ``` 815 | 816 | ![firebase storage rules edit](https://github.com/Hiro-mackay/react-bootcamp/blob/bootcamp-3/assets/firebase_storage_rules_edit.png?raw=true) 817 | 818 | `match /b/{bucket}/o `がこのストレージ全体のパスを指定しています。 819 | 820 | `match /videos/{allPaths=**} `が、ストレージ内の`/videos`内のディレクトリに存在する全てのファイルとディレクトリを指定しています。 821 | 822 | その中で、`allow read`は全てのリクエストを許可しています。 823 | 824 | 反対に、`allow write: if request.auth != null`はリクエストがログインされたユーザーのみ許可する形にしています 825 | 826 | firebase storage では、リソースにアクセスするときに、自動的に request に様々なデータを付与してリクエストを開始します。 827 | 828 | 例えば、ログイン済みのユーザーからのリクエストであれば、自動的に`request.auth`に認証情報が格納されます。 829 | 830 | 今回はこの情報の有無を確認して、ログイン済みユーザーであるかを確認して条件分岐しています。 831 | 832 | `thumbnails`も同じような条件で記述しています。 833 | 834 | これで、ログイン済みのユーザーのみがアップロードが許可され、他の未認証ユーザーは読み込みのみのセキュリティルールを構築できました。 835 | 836 | これまでの設定を保存するために、「公開」をクリックして設定を反映させます。 837 | 838 | 続いて、React でこの Firebase Storage を呼び出します。 839 | 840 | ```TS 841 | // src/utils/Firebase/storage.ts 842 | 843 | // firebase のstorageをimport 844 | import { storage } from "./config"; 845 | 846 | /** 847 | * 必要最低限のアップロード用関数 848 | * @param ref : アップロードするファイルの参照を指定する。例:'videos/example.mp4' 849 | * @param file : アップロードするファイルそのもの 850 | * @returns firebase.storage.UploadTask を返す 851 | */ 852 | export const uploader = (ref: string, file: File) => 853 | storage.ref().child(ref).put(file); 854 | 855 | /** 856 | * 必要最低限のダウンロード用関数 857 | * downloader()で取得したURLは、