この記事は「【マイスター・ギルド】本物のAdvent Calendar 2021」1日目の記事です。
本記事ではFastAPI + Reactを使ったシンプルなフルスタックアプリの実装方法の紹介および所感を行っていきます。
想定読者
- React + TypeScriptの基本的な書き方を理解されている方。
- FastAPIに初めて触れる方。
- React + FastAPIで実装してみたい方。
今回のゴール
- 簡単なCRUD処理を実装する。
- 記事の管理を想定。
- ユーザー認証機能はなし。
開発環境
- PC: MacBook Pro(Apple M1, 2021)
- OS: macOS Big Sur 11.4
- フロントエンド:
- Node.js 16.10
- React 17.0.2
- Typescript 4.1.2
- バックエンド:
- Python 3.9.7
- FastAPI 0.70.0
執筆の経緯
自分は普段フロントエンドをやらせていただいている身ですが、ここ最近バックエンドの仕組みを知りたくなってきた、かつ担当範囲を広げたい気持ちが高まってきており、バックエンドも今回のアドベントカレンダーをきっかけに、今後ちゃんとやっていかないと、と考えるようになりました。
そんな流れでバックエンド殆どやっていない自分でも扱えそうなWeb frameworkを探していたところ、FastAPIで書いていくことに決めました。その理由が
- 元々1年くらい前に興味本位でPython3を書いていた時期があった。
- 型定義前提になっている(Python3で型定義できる事自体、FastAPIに触れてから初めて知りました)。
- 小さい規模から扱える。
- ドキュメントがかなり充実しており、公式からの情報提供も多い。
また今回アプリを作成するにあたり、フロント側は経験のあるReactを使いますが、せっかくなので使ったことのないライブラリ/やったことのないディレクトリ構成を試しました。
作成したアプリの概要
作成したアプリのリポジトリはこちら。
興味ある方はリポジトリをクローンして実際に動かしてみてください。
PRも大歓迎します。
使用フレームワーク
React(フロントエンド)
フロントエンド側はReact + TypeScriptで作成しました。
以下使用したライブラリとなります。
- axios(APIのfetch用)
- react-helmet-async(ページタイトル指定)
- React Query(State管理)
- React Router(ルーター周り、最近リリースされたばかりのversion6系を使用)
- Jest/Testing Library(ユニットテスト)
CSS周りについてはUIライブラリやフレームワークは使わず、SCSSで統一しました。
また今回の作成にあたり、ディレクトリ構成やライブラリ選定については以下のリポジトリを参考にさせていただきました。後ほどディレクトリ構成も紹介しますが、ほぼ踏襲した形にしています。
解説記事はこちら。
FastAPI(バックエンド)
FastAPIはPythonのWeb frameworkの1つとなります。
PythonのWeb frameworkといえばDjango/Flaskが有名ですが、こちらは2018年に誕生と比較的歴史が浅いにも関わらずGitHubのスター数が4万近く(2021/11時点)と今大きく伸びているWeb frameworkです。
その大きな特徴として
- Pythonの型定義機能をベースに実装(型定義の仕方自体がTypeScriptに近いので個人的にも馴染みやすい)。
- シンプルな方法でAPIを定義/実行できる。
- APIサーバーを立ち上げるとSwagger UIが自動生成され、定義したAPIをすぐ参照できる。
今回実装したアプリのSwagger UIを立ち上げた様子です。「Try it out」ボタンを押下することで、実際にAPIを実行させることも可能です。
API定義の仕方
- シンプルなGETメソッドの実装
まずmain.py
にsimpleという単純な文字列を返すメソッドを定義します。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def simple():
return {"message": "Hello World!!!"}
そして次のコマンドを叩くとAPIサーバーが起動します(ちなみに--reload
を指定しておくことでpyファイルの更新のたびにAPIサーバーも更新されるようになります)。
uvicorn main:app --reload
するとこのURLでAPIサーバーが立ち上がったよのメッセージが出るので、http://127.0.0.1:8000 のリンクに飛ぶと次のJSONが表示されます。
{"message": "Hello World!!!"}
軽くAPI実装するだけならこれだけで実装できます。
その他のAPI実装パターン
上記で紹介したパターン以外のAPI実装の仕方については以下の記事が詳しいのでこちらに任せます。FastAPIをガッツリ活用していきたい方は是非読んでください。
公式ドキュメントも(一部英語残っていますが)日本語訳されており、チュートリアルが充実しているので上記記事と並行して読むことをお勧めします。
その他以下の資料も参考にしました。
- Developing a Single Page App with FastAPI and React
- FastAPI - A python framework | Full Course ※YouTube動画
また自分からもFastAPIの勉強がてら実装した例集も貼っておきます。
その他使用したライブラリ/ソフト
- pytest(ユニットテスト)
- SQLite(データベース)
- SQLAlchemy(ORM)
- TablePlus(データベース操作用のソフト ※無料版)
ディレクトリ階層
ディレクトリ階層は以下の形にしました。
.
├── backend <!-- バックエンド用ディレクトリ -->
└── frontend <!-- フロントエンド用ディレクトリ -->
バックエンド
backend
├── app
│ ├── tests <!-- ユニットテスト用 -->
│ │ ├── __init__.py
│ │ └── test_api.py <!-- api.pyのユニットテストコード -->
│ ├── __init__.py
│ ├── api.py <!-- APIの定義 -->
│ ├── database.py <!-- sqlite設定用 -->
│ ├── schemas.py <!-- APIにリクエスト値として設定するschemaを定義 -->
│ └── models.py <!-- APIから返却されるmodelを定義 -->
├── app.db <!-- sqlite用ファイル(ローカルサーバー用) -->
├── test.db <!-- sqlite用ファイル(ユニットテスト用) -->
├── main.py <!-- FastAPIの立ち上げ用ファイル -->
├── README.md
└── requirements.txt
フロントエンド
今回はcreate-react-appコマンドで生成しての実装だったため、直接編集していないファイル/ディレクトリの記載は省略します。
featuresフォルダに関しての詳しい役割は、前述のbulletproof-react解説記事を参照にしてもらえばと思います。
frontend
└── src
├── components <!-- コンポーネント置き場 -->
│ ├── Elements <!-- buttonやlinkなど汎用的に使うコンポーネント置き場 -->
│ ├── Header
│ └── Layout
├── features <!-- アプリケーション各機能の名称のディレクトリを設置 -->
│ ├── articles
│ └── sample
├── lib <!-- 外部ライブラリ設定 -->
│ └── axios.ts
├── routes <!-- ルーター設定 -->
│ ├── index.ts
│ └── public.ts
├── App.scss <!-- 今回のcssクラスをすべて定義 -->
└── App.tsx <!-- メインのtsxファイル -->
実装で苦労したこと
正直今回はバックエンドよりずっとフロントエンドの実装に苦労しました。
バックエンドはほぼ公式ドキュメントだけで基本解決でき、UPDATEメソッドの実装で少し困った程度で済んだのですが、フロントエンドに関しては
- 参考元のbulletproof-reactの理解に時間がかかった。
- React Queryについては使用したのが初めてかつチュートリアルに触れずにやった状態だったため使い方の理解に苦労した。
- React Routerにおいて、ベタに
<Routes>〜</Routes>
で囲うのではなく、useRoutes
を使った実装自体が初めてで模索しながらの実装だった。 - 慣れてない状態で、ベースとなるコンポーネントをAtomic Design寄りな設計にした。
の4点があったことが原因です。
ただ実装方法の理解に苦労した分、以下の恩恵も得ることができました。
- 今まで存在は知っていたが使う機会がなかったライブラリを初歩程度とはいえ一応扱えるようになった(React Queryなど)。
- Atomic Design寄りなコンポーネント設計に沿った実装を一通り理解した。
- bulletproof-reactの理解を通じて、これまであまり手を付けてこなかったReal World系の他リポジトリの理解も深めようと思ういい機会になった。
今後やっていきたいこと
フロントエンド
Reactはそこそこ書いてきたつもりでしたが、今回初めて知った便利なライブラリも多く、React界の奥深さを改めて感じました。
課題を踏まえて、今後やりたい/改善させたいことは以下の通りです。
- React Routerについては、Version 6になって新しく登場したメソッドが追いきれてない。公式APIリファレンスを参考にしながら今後もスムーズに扱えるようになっていきたい。
- 同じ会社から最近でたRemixというフルスタックフレームワークも参照元としては良さそう。
- バックエンドのユーザー認証が一通り扱えるようになったら、フロントエンドもログイン機能、ログインの有無でレイアウトを変えるなどのロジックを入れていきたい。
- 時間的制約で断念したライブラリの導入を今後行っていきたい。
- E2Eテスト用のCypress。
- コンポーネント管理用のStorybook。
- 今回作成したベース用のコンポーネントは徐々に改善させつつ今後使い回せるようにしたい。可能ならnpmパッケージにもしたい。
- Material-UI改めMUIは今回の実装に近い書き方になっているため参考になりそう。
バックエンド
いわゆるCRUD機能しか触っていない状態のため、まずは「ユーザー認証実装を学ぶ」→「freeCodeCampのAPIフルコースを完走する」の順に考えています(※いずれもReactなどフロントエンドのフレームワークとセットで実装する予定)。
ユーザー認証の実装
参考にしたページにも貼ってあるFastAPI - A python framework | Full Courseでは後半ユーザー認証を使った実装が紹介されており、まだ取り組めていないのでこれをベースに学習する予定です。
JWT (JSON Web Token)とかOAuth2など全然わかっていないので、概要を理解しつつ実装できるようになりたいです。
freeCodeCampの動画
海外ではかなり有名なfreeCodeCampのYouTubeチャンネルで最近FastAPIを使ったPythonのバックエンド実装の動画(なんと19時間超え!)が公開されたので時間をとってこれをまず完走しようと思っています。
動画の内容を一部抜粋すると以下になります。全編無料で本当にいいのか疑うレベルの充実ぶりです(バックエンド経験全然な自分が乗り越えられるか正直不安でしかない…)。
- Postgres SQLへの接続/参照
- SQLAlchemyとPostgres SQLをセットで使う
- Herokuを使ったデプロイ
- Docker周りの設定
- GitHub Actionsを使用したCI/CDの設定
本記事は以上となります。