React(Vite), FastAPI, Dockerで環境構築

スポンサーリンク

事前準備

  • Python、Node.js、Docker Destop(Windows)をインストールしておく

フォルダ作成

  1. 適当な階層に新規フォルダ「react-fastapi-docker」を作成し、VSCodeで開く
  2. プロジェクトフォルダ直下に「frontend」「backend」フォルダを作成
react-fastapi-docker/
├── frontend/
└── backend/

フロントエンドのセットアップ

  • VSCodeのターミナルタブから新規ターミナルを開き、frontendフォルダの階層で下記を実行
npm create vite@latest
  • 入力を求められた際は下記を選択
Project name.
Select a frameworkReact
Select a variantTypeScript + SWC
ターミナル画面
PS C:\Users\source\test\react-fastapi-docker\frontend> npm create vite@latest

> npx
> create-vite

? Project name: » .

? Select a framework: » - Use arrow-keys. Return to submit.
    Vanilla
    Vue
>   React
    Preact
    Lit
    Svelte
    Solid
    Qwik
    Angular
    Others

? Select a variant: » - Use arrow-keys. Return to submit.
    TypeScript
>   TypeScript + SWC
    JavaScript
    JavaScript + SWC
    React Router v7 ↗
  • 続いてfrontendフォルダの階層で下記を実行
npm install

下記のようにフォルダ・ファイルが生成される

frontend/
├── node_modules/
├── public/
├── src/
├── .gitignore
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── README.md
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
  • 下記コードを実行し、Reactアプリの起動を確認
npm run dev

バックエンドのセットアップ

・backendフォルダの階層で下記を実行

python -m venv env
  • 仮想環境をアクティブ化し、fastapi, uvicornをインストール
PS C:\Users\source\test\react-fastapi-docker\backend> .\env\Scripts\activate
(env) PS C:\Users\source\test\react-fastapi-docker\backend> pip install fastapi uvicorn
  • main.pyファイルを作成し、簡単なAPIを作成
backend/
├── app/
│   ├── main.py
└── env/
# main.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel

app = FastAPI()

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

@app.get("/api/hello")
async def read_root():
    return {"message": "Hello from FastAPI"}
  • backendフォルダの階層で下記コードを実行し、APIの実行確認
uvicorn app.main:app --reload
  • ブラウザで「http://127.0.0.1:8000/api/hello」にアクセスし、出力の確認
{"message":"Hello from FastAPI"}
  • 下記コマンドを実行し、インストール済みパッケージ一覧を出力する
pip freeze > requirements.txt

ReactからAPIの呼び出し

  • /frontend/src/App.tsxを修正し、FastAPIを呼び出す機能を実装する
import { useState, useEffect } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0);
  const [apiMessage, setApiMessage] = useState<string | null>(null);

  useEffect(() => {
    const fetchMessage = async () => {
      try {
        const response = await fetch('http://localhost:8000/api/hello'); // FastAPIのエンドポイント
        const data = await response.json();
        setApiMessage(data.message); // メッセージを状態に保存
      } catch (error) {
        console.error('Error fetching the API:', error);
        setApiMessage('Failed to fetch data from API');
      }
    };

    fetchMessage();
  }, []);

  return (
    <>
      <div>
        <a href="https://vite.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <div className="api-message">
        <h2>Message from FastAPI:</h2>
        <p>{apiMessage || 'Loading...'}</p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App
  • frontendフォルダの階層で下記コマンドを実行し、ビルド
npm run build

Dockerの準備

  • backendフォルダ直下に下記Dockerfileを作成
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt /app/
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app /app/
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
EXPOSE 8000
  • frontendフォルダ直下に下記Dockerfileを作成
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
  • projectフォルダ直下に下記docker-compose.ymlファイルを配置
version: '3.9'
services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:80"
    volumes:
      - ./src:/app/src
      - ./public:/app/public
    stdin_open: true
  • ディレクトリ構造は下記のようになる
react-fastapi-docker/
├── backend/
│   ├── app
│   │   ├── main.py
│   ├── Dockerfile
│   └── requirements.txt
├── frontend/
│   ├── src
│   ├── ...
│   ├── Dockerfile
└── docker-compose.yml

Dockerによるアプリの起動

  • プロジェクトフォルダの階層で下記コマンドを実行してアプリを起動
docker-compose build
docker-compose up
  • http://localhost:3000/にアクセスしてアプリの起動を確認

FastAPIの呼び出しもうまくいっている

コメント

タイトルとURLをコピーしました