🕌

【完全版】React + FastAPIで開発するモダンなwebアプリ

2022/05/20に公開
1

はじめに

フロントエンドはリッチに作りたい!だけどバックエンドはFirebaseだけじゃなくてpythonでも書きたい...

そんな悩みを一度は抱いたことがあるのではないでしょうか?
今日はそんな要望に答えるべく、ゼロから始めるReact✕FastAPIと題しまして、フロントエンドはReact、API側はpythonで作ってリッチなwebアプリを作っていきましょう。

なぜReact?

Reactは、Javascriptのフレームワークの一つです。同種のフレームワークとして、Vue.jsやAngular.jsが挙げられますが、Googleでの検索数も、githubの利用者数もReactが一番多く、注目度は高い言えます。webのフロントエンドを触る上で、是非習得したいフレームワークと言えると思います。

なぜFastAPI?

今回は、APIをPythonのフレームワーク、FastAPIで作ることにします。実はPythonにはDjangoやFlaskなどの一般的によく使用されるフレームワークが存在しているので、

なぜFastAPI?

と思われた方もいるのではないでしょうか。確かに、DjangoやFlaskを用いてフルスタックにwebアプリを構築する方法や、それらのフレームワークのAPIモードを用いてAPIだけを作成するやり方もあります。
しかし、これらのフレームワークは最初からAPIを作ることを想定して設計されたフレームワークではなく、どうしてもAPIを作る上で必要ない部分の機能が数多くあります。

その点、FastAPIはPythonでAPIを作ることを前提に設計されたフレームワークで、FastAPIにしかない機能が多くあります。(有名なものとしては型チェックや、APIリファレンスの自動生成などがあります)

現在のWebアプリ開発では、大規模なフレームワークを用いてフルスタックに開発するというよりも、フロントエンドとバックエンドの処理を別々に分けて開発する方が主流になりつつあります。フロントエンドはリッチなReact、APIはFastAPIを用いて開発することで、モダンなwebアプリ開発ができると思います。
また、APIを作る言語にPythonを選択することで、AIを利用したアプリを作りやすいというメリットもあります。(pythonはAI回這うtで一番といっていいほどよく使用される言語です)

始め方

フロントエンド(React)

1. Reactの原型を作る

まずは、Reactのスターターを利用し、テンプレートを自動で生成します。今回は、詳しいコマンドの説明は割愛します。

$ npx create-react-app undou-front
$ cd undou-front

ここでは、名前はundou-frontとしました。みなさんの好きな名前をつけてください。

2. サーバーを起動

実は、1番のコマンドをうっただけで、デフォルトのReactアプリが自動で生成されており、ローカルのサーバーを起動することができます。早速起動してみましょう。

$ yarn start

yarnではなくnpmを用いたい方は、npm startと打ってください。

サーバーが起動できたら、http://localhost:3000/にアクセスしてみましょう。デフォルトで画面が開かれるかもしれません。
このような画面が出力されれば成功です。

デフォルトの画面

3. APIを利用するための便利なライブラリをインストール

Reactでは、便利なライブラリをインストールすることで、様々な機能を簡単に実装することができます。
今回は、API通信を簡単に実装できる、axiosというライブラリをインストールします。

$ yarn add axios

npmを使いたい方は、npm install axiosと打ってください。

4. デフォルトの画面を削除

create-react-appを実行すると、デフォルトの画面が自動で生成されるのですが、今はFastAPIとの通信を実装したいので、シンプルにするために削除します。
srcディレクトリの中の、App.jsApp.jsxに変更します。jsxというのは、React特有の拡張子です。
App.jsxはデフォルトでこのようになっていると思います。

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

いらない部分を消します。そうすると、以下のようにしてくだいさい。
App.jsx

import React from "react";

function App() {
    return (
        <div>
            <div>ここに処理を書いていきます</div>
        </div>
    );
}

export default App;

ローカルサーバーを起動(yarn start)し、http://localhost:3000/を表示してみましょう。

こんな画面が表示されたらOKです(上の黒い棒は気にしないでください)。
これで準備はOKです。後ほどaxiosを利用して、API通信をしていきます。

API(FastAPI)

1. ディレクトリ作成&pythonの仮想環境構築

$ mkdir undou-back
$ cd undou-back

pythonの仮想環境は、venvと呼ばれます。pythonのバージョンは同じですが、ライブラリの構成を環境ごとにわけることができるため、便利です。

$ python -m venv venv

これで仮想環境を構築します。
次に、仮想環境に入ります。
シェルにFishを使っている方は、

$ . venv/bin/activate.fish

と打ってください。
Zshやbashを使っている方は、

$ . venv/bin/activate

と打ってください。おそらくうまくいくと思います。

2. 必要なライブラリをインストール

FastAPIを使う上で必要なライブラリは2つあります。

  • fastapi
  • uvicorn

の2つです。fastapiはFastAPI本体で、uvicornはローカルで動くサーバーです。この2つのライブラリがないと動作しないので、忘れずにinstallしましょう。

$ pip install fastapi uvicorn

3. 基本的なAPIの作成

今回は、基本的なAPIの作成をします。
main.pyを作りましょう。

$ touch main.py

main.pyが作成できましたら、次のように中身を書いてみてください。

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost:3000",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def Hello():
    return {"Hello":"World!"}

簡単にコード解説をします。詳しい説明は、わかりやすい公式のチュートリアルがあるので、そちらを参照してみてください。
https://fastapi.tiangolo.com/ja/tutorial/first-steps/

from fastapi import FastAPI

app = FastAPI()

この2行は、決り文句でして、はじめにfastapiからFastAPIを読み込み、クラスをインスタンス化してappという変数に代入します。あまり深く考えずに、覚えていいと思います。

from fastapi.middleware.cors import CORSMiddleware

origins = [
    "http://localhost:3000",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

このコードは、主にセキュリティ面のコードです。Reactのアプリケーションと通信する際には、必要になります。
最初にfastapiからCORSMiddlewareを読み込んだあとに、URL別にアクセスできる権限を付与しています。
origins = [][]の中に、通信するreactなどのアプリのURLを記載しましょう。最初はlocalとの通信をしたいので、http://localhost:3000しか登録していませんが、後ほどフロントエンドのアプリをサーバーにデプロイした際には、URLを増やすことになると思います。

@app.get("/")
def Hello():
    return {"Hello":"World!"}

最後に、このコードについて説明してきます。もし、Flaskを使用したことがある方は、見覚えがあるかもしれません。FastAPIはFlaskとだいぶ似ています。

@app.get("/")

このコードは、/というURLにGetリクエスト来たら、という意味です。/はデフォルトのURLです。
Getリクエストは、webのリクエストの一つで、主にデータを取得したいときにクライアントから送られます。この場合のクライアントは、フロントエンドのアプリです。

def Hello():
    return {"Hello":"World!"}

ここでは、{"Hello":"World!"}というjsonを返すように設定しています。このように、FastAPIでは、returnにjsonを書くだけで、json形式でレスポンスを送る事ができます。

4. ローカルサーバーを起動

では、ローカルサーバーを起動しましょう。当然ですが、サーバーを起動しないと、APIは作動しません。ここで、最初にインストールしたuvicornを使用します。
下記のコマンドを打ってください。

$ uvicorn main:app --reload

--reloadオプションをつけることで、コードを更新すると自動でサーバー側も更新してくれます。
それでは、http://127.0.0.1:8000/にアクセスしてみましょう。

こんな画面が表示されたら成功です。

5. FastAPIの便利機能

これは付録みたいなものですが、FastAPIには便利な機能があるので紹介したいと思います。
サーバーを起動した状態で、http://127.0.0.1:8000/docsにアクセスしてみましょう。

FastAPIが自動で生成

このように、FastAPI側が自動でAPIのリファレンスを作成してくれます。便利ですよね!

これでAPI側の処理は完成しました。あとは、フロントエンド側(React)でAPIを呼び出して見ましょう。

ReactからFastAPIを呼び出す

では、ReactからAPIを呼び出して見ましょう。
APIを呼び出すには、先程インストールしたaxiosを使います。

App.jsxを以下のように編集しましょう。

import React from "react";
import axios from "axios";

function App() {
	const [data, setData] = React.useState();
	const url = "http://127.0.0.1:8000";

	const GetData = () => {
		axios.get(url).then((res) => {
			setData(res.data);
		});
	};
	return (
		<div>
			<div>ここに処理を書いていきます</div>
			{data ? <div>{data.Hello}</div> : <button onClick={GetData}>データを取得</button>}
		</div>
	);
}

export default App;

簡単にコードの説明をしていきます。

import axios from "axios";

ここで、axiosを読み込んでいます。

const [data, setData] = React.useState();

ReactのuseState()を使用しています。

useState()って何?という方は、Reactの公式チュートリアルを参考にしてみてください。

axios.get(url).then((res) => {
  setData(res.data);
})

axiosを利用して、urlにgetリクエストを送っています。今回は、uvicorn main:app --reloadで立ち上げたFastAPIにリクエストを送るため、http://localhost:8080をurlに定数として代入しています。

thenって何?という方は、JS Promiseと検索してみるとわかりやすい記事がたくさん有ります。

setData(res.data);

この部分で、stateであるdataを更新しています。この時点ではじめてdataに値が入ります。

どんな値が入るか考えてみましょう。

dataには、以下のようなjson形式のデータが入ります。

{"Hello":"World!"}

これは、FastAPIでこのようなレスポンスを返すように設定したからです。
このJson形式のデータは、"Hello"がキーで、"World!"が値と見ることができます。Javascriptでは、.のあとにキー名を指定することで、そのキーのバリューを取得する事ができます。(Javascriptのオブジェクトと似ています)

<div>
  <div>ここに処理を書いていきます</div>
  {data ? <div>{data.Hello}</div> : <button onClick={GetData}>データを取得</button>}
</div>

ここが、実際にwebページに表示される部分です。

  {data ? <div>{data.Hello}</div> : <button onClick={GetData}>データを取得</button>}

このコードは、三項演算子と呼ばれる記法を用いています。

{if文のような条件式 ? trueだった場合の処理 : falseだった場合の処理}

のように書きます。今回は、dataが存在する場合は、data.Helloを表示し、ない場合は、データを取得するボタンを表示します。
では、ブラウザで見てみましょう。

yarn start

を打って、http://localhost:3000を開きます。

フロントエンドのアプリを起動する際に、FastAPIも起動することを
忘れないようにしましょう

最初はこんな画面が表示されると思います。

では、データを取得ボタンをクリックしてみましょう。

このように、データを取得ボタンがWorld!という文字に変わったら成功です!

本番環境にデプロイしてみよう

これまでの開発は、すべてローカルと呼ばれるいわゆる自分のパソコンの中だけで実装してきました。なので、あなた以外の人はあなたのアプリを操作したり開いたりすることができません。
あなた以外の人たちがアクセスできるようにするには、ローカルではなくサーバー上でアプリを動かす必要があります。
ですので、これからサーバー上にwebアプリを置きたいと思います。サーバーにローカルで開発したアプリを置くことを、デプロイといいます。

サーバーにデプロイするためには、当然サーバーが必要になります。しかし、自分でサーバーを持ってるよ、という方は少ないのでは無いでしょうか?
サーバーは高価なものなので、実際に購入しようとすると何百万~という値段がします。自前でサーバーを用意することを、オンプレミスでの開発といったりします。
高価なので、個人開発ではクラウドのサーバーを利用することが一般的です。

今回は、無料でクラウドのサーバーが使えるサービス、Herokuを用いてFastAPIをデプロイし、フロントエンドは無料で使えるVercelというサービスを用いてデプロイしたいと思います。

FastAPIをデプロイ

まずはじめに、FastAPIをデプロイしていきます。
Herokuの登録がまだの方は、アカウント登録しましょう。アプリの数が5個までのうちは無料なので、安心して下さい。

次に、Herokuにローカルのパソコンの環境からデプロイするために、2つのツールを導入します。

  1. Git
  2. Heroku CLI

Gitは、世界中で使われているコードのバージョン管理ツールで、アプリケーション開発をする上では必須になります。
Heroku CLIは、Herokuをコマンドで操作できるツールです。
それでは、2つのツールをインストールします。

Git

まずは、ターミナルもしくはコマンドプロンプトを開いて、

git --version

と打ってみましょう。

git version 2.32.0

のように、git version ~と出たら、Gitがパソコンにインストールされています。次に進みましょう。
それ以外の出力が表示された方は、Gitのインストールが住んでいないので、Gitをインストールしていきます。
下記の記事が非常に参考になります。

Heroku CLI

Heroku CLIのインストール方法は、公式が参考になります。
https://devcenter.heroku.com/ja/articles/heroku-cli

Macの方は、以下のコマンドをターミナルに打ち込みます。

​brew tap heroku/brew && brew install heroku

Homebrewがはいっていることが前提になります。

Windowsの方は、先程の公式ページを開いて、公式ダウンローダーからインストールします。

デプロイ

では、FastAPIのコマンドを開いて、デプロイしていきます。
Herokuでは、mainのコードに加えて、以下のファイルが必須になります

  • requirements.txt
  • Procfile

requirements.txtは、pipでインストールしたpythonのライブラリを記載するファイルです。デプロイする際に、heroku側がこのファイルを見てライブラリをインストールし直します。

Procfileは、herokuにデプロイしたあとに、サーバーを動かすコマンドを書くファイルです。ローカルでは、下記のコマンドを打ちましたが、

uvicorn main:app --reload

heroku側では、少し違ったコマンドを指定する必要があります。
uvicornではなく、gunicornというライブラリを使用してサーバーを起動します。

gunicornはpythonのライブラリとしてimportします。

では、簡単に流れを説明します。

  1. gunicornpipでインストール
  2. Procfileを記述
  3. requirements.txtを作成
  4. Gitでプロジェクトを管理
  5. Heroku CLIを用いてHerokuにデプロイ

順番に解説します。

1. gunicornpipでインストール

まずは、gunicornをインストールします。
下記のコマンドを打ってください。

pip install gunicorn

これで、インストールすることができました。

2. Procfileを記述

次に、Procfileを記述します。Procfileには、Heroku側で実行するサーバーを起動するためのコマンドを打つのでしたね。
プロジェクトの直下の場所に(main.pyと同じ階層です)、Procfileを作成します。拡張子はないので注意してください。中身を記述します。gunicornを用いてサーバーを起動するコマンドです。特に覚える必要はないと思います。

Procfile

web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app

これで大丈夫です。

3. requirements.txtを作成

次に、requirements.txtを作成しますHeroku側がPythonのライブラリをインストールできるように、pipでインストールしたライブラリを記載します。手動で書き込んでもいいのですが、pipには便利なコマンドがあるので、これをターミナルに打ち込んでください。

requirements.txtを作成する必要はありません。このコマンドを打つだけで自動で作成されます。

pip freeze > requirements.txt

これで、requirements.txtが自動で作成されました。中身を見てみましょう。

requirements.txt

anyio==3.6.1
asgiref==3.5.2
click==8.1.3
fastapi==0.78.0
gunicorn==20.1.0
h11==0.13.0
idna==3.3
pydantic==1.9.1
sniffio==1.2.0
starlette==0.19.1
typing_extensions==4.2.0
uvicorn==0.17.6

このように、pipを用いてインストールしたライブラリの一覧と、そのバージョンを自動で書き込むことができます。
これでrequirements.txtは完成です。

4. Gitでプロジェクトを管理

次は、Gitを用いてプロジェクトの管理をしましょう。GitはHerokuにデプロイする上でも必要ですが、後にVercelにデプロイする際にも必要になってきます(VercelにデプロイするときにはGithubが必要なので)。
**Gitはどの言語で何をする上でも必ず必須になる便利なツールです。**一度基本的なコマンドを練習してある程度使いこなせるようになっておくのがベストです。今回は、Gitの講座ではないので、コマンドを逐一説明することはしません(今後Gitの講座もやろうと考えています)。

では、プロジェクトのターミナルで、以下のコマンドを上から順番に打ってください。

git init
git add .
git commit -m "initial commit"

この3つのコマンドを打ち終えたら、Gitの処理は終了です。
次は、いよいよ最後です。Herokuにデプロイしていきましょう。

5. Heroku CLIを用いてHerokuにデプロイ

最後に、Heroku CLIを用いてHerokuにデプロイしましょう。はじめての方は、Herokuにログインする必要があるので、ターミナルで以下のコマンドを打ちましょう。

heroku login

自動でブラウザが立ち上がると思うので、支持にしたがってログインしましょう。
すでにHeorku CLIを使ったことがある方は、このステップは飛ばして大丈夫です。

では、Herokuのアプリをコマンドから作成します。

heroku create

と打ってください。
そうすると、こんな出力がされると思います。

Creating app... done, epoita-itjei-29832
https://epoita-itjei-29832.heroku.app.com/ | https://git.heroku.com/epoita-itjei-29832.git

このような画面が出たらherokuで新しいアプリを作ることに成功しました。では、実際にこのherokuのアプリにローカルのアプリ(FastAPIで作成したAPI)をデプロイしましょう。
下記のコマンドを打ちましょう。

git push heroku master

このコマンドを打つと、自動でherokuのデプロイが始まります。長い長い出力の最後に、このような出力が表示されたら成功です。

remote: Verifying deploy... done.
To https://git.heroku.com/epoita-itjei-29832.git
  592et3...95et74s master -> master

これで、ローカルのFastAPIのアプリを、Herokuにデプロイすることができました!

Reactアプリをデプロイ

Reactアプリは、Vercelという便利なサービスにデプロイします。Vercelは無料で使えるのでとてもおすすめです。

https://vercel.com/

Githubと連携するのが一番効率的なので、Githubにリポジトリを作成し、pushします。
【手順】

git remote -v githubのレポジトリのURL
git push origin master

pushし終えたあとに、VercelでNew Projectを押します。
Import Git Repositoryから先程作成したリポジトリをimportします。importしたあとに、deployを押すとデプロイが完了します。

Vercelを使用すると、なんとこれだけでデプロイが完了します!

あとは、Vercelでデプロイしたプロジェクトを開き、Visitをクリックします。
そうすると、ローカルではなくパブリックなURLでwebアプリが表示されるのではないでしょうか?
これで、Reactアプリのデプロイは完了です!

注意

FastAPI、React共にデプロイできたと思います。しかし、Vercelからreactのアプリを起動し、データを取得ボタンを押しても何も起こらないと思います。それは、URLが変わってしまっているからです。
ReactアプリのApp.jsxを開いてください。

import React from "react";
import axios from "axios";

function App() {
	const [data, setData] = React.useState();
	const url = "http://127.0.0.1:8000";

	const GetData = () => {
		axios.get(url).then((res) => {
			setData(res.data);
		});
	};
	return (
		<div>
			<div>ここに処理を書いていきます</div>
			{data ? <div>{data.Hello}</div> : <button onClick={GetData}>データを取得</button>}
		</div>
	);
}

export default App;

URLが変わっているため、

const url = "http://127.0.0.1:8000"

を変更する必要があります。HerokuのURLを参照して、各自変えましょう。

そして、FastAPI側でもURLを変える必要があります。
main.appを開いてください。

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://localhost:3001",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def Hello():
    return {"Hello":"World!"}

ReactアプリのURLが変わっているため、

origins = [
    "http://localhost:3001",
]

ここの、originsのリストに、VercelのURLを追加する必要があります。下記に、例を示します。
【例】

origins = [
    "http://localhost:3001",
    "https://test-app.vercel.com",
]

このように、URLが変わるとフロントエンドとAPI側の2つの箇所を変更する必要があります。

忘れがちになりやすいので、注意しましょう。

2箇所を無事に変更できたら、デプロイを更新しましょう。
Reactアプリの場合は、githubに変更をpushするだけで、Vercelが自動でデプロイを更新してくれます。便利ですよね!

FastAPIの場合は、Herokuにpushします。コマンドは以下のとおりです。

git push heroku master

これで、herokuもデプロイの更新が完了しました。

VercelでデプロイしたURLを開いてみましょう。
データを取得ボタンを押したときに無事World!とひょうじされていれば完成です!お疲れさまでした

終わりに

以上で、ReactとFastAPIを用いたモダンなwebアプリケーションを開発するための基礎を作り終えることができました。この流れをしっかり抑えたうえで、FastAPI側でAIを実装してみたり、ReactではなくNextJSを用いてみたりなど、応用を効かせてみると良いかもしれません。
それでは、おつかれ様でした!

Discussion

studiopfstudiopf

詳しい解説ありがとうございます。
ただ、WSL2+Ubuntuで実際に動かしてみたところ、エラーで通信できませんでした。
main.pyの
allow_origins=origins

allow_origins=["*"]
に変更することでエラーはなくなりました。