【超入門】ReactとPython(FastAPI)で簡単な四則演算アプリを作ろう!

【超入門】ReactとPython(FastAPI)で簡単な四則演算アプリを作ろう!

ReactとPython(FastAPI)を利用した四則演算アプリを作成してみました!
非常に簡単なアプリとなっておりますので、未経験の入門として真似してみると良いかなと思います。

目次

四則演算アプリのサンプル

今回作成するアプリのサンプルは、画像のようなアプリになります!
[https://terakoya.hack-lab.app/portfolio/calculator]に動かせるサンプルを置いていますので、気になる方は触ってみてください。

Reactで四則演算アプリのUIを作る

まずは、Reactを利用して四則演算のUIを作っていきます。
利用するライブラリ等は下記に記載しておきます。

  • react-bootstrap(bootstrap):CSSライブラリ

create-react-appでひな形を作成

まずは、Reactのお決まりである「create-react-app」コマンドを利用して、ひな形のアプリを作ります。

$ npx create-react-app react-app --template typescript

少し待つ必要がありますが、完了すると、下記の内容が出力されているはずです。

・・・

  cd react-app
  npm start

Happy hacking!
npm notice
npm notice New minor version of npm available! 10.8.2 -> 10.9.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.9.0
npm notice To update run: npm install -g npm@10.9.0
npm notice

記載の通りに、実行してみます。

$ cd react-app/
$ npm start

下記の画面が表示されれば、ひな形の作成は完了です。

不要なコードやファイルを削除

初期画面は、色々邪魔なものも多いので、不要なものを削っていきます。

まずは、「index.tsx」を下記のように修正してください。

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

次に「App.tsx」も不要なコードが多いため、最小限のコードにしていきます。

import './App.css';

function App() {
  return (
    <div className="App">
      HELLO WORLD
    </div>
  );
}

export default App;

次に、下記のファイルは、今回は利用しないため削除します。

  • App.test.tsx
  • logo.svg
  • reportWebVitals.ts
  • setupTests.ts

ここまで出来たら、再度アプリを起動してみます。

$ npm start

先ほどより、かなり質素になりましたが、これでいったん大丈夫です。

Bootstrap(react-bootstrap)を利用できるようにする

ここまでできたら、Bootstrapを利用できるようにしていきます。
Bootstrapが何かは、調べてみるといいかもしれません。簡単に言うと、綺麗なUIを簡単に実現できるようにするためのライブラリになります。

Bootstrapは、ウェブサイトやウェブアプリケーションのデザインを簡単にするためのCSSフレームワークです。Twitter社のエンジニアが開発したもので、CSSやJavaScriptの機能をまとめたテンプレートやコンポーネントが豊富に含まれており、デザインの標準化とコーディングの効率化を目指しています。

まずは、npmでreact-bootstrap bootstrapをインストールしましょう。

$ npm install react-bootstrap bootstrap

次に、「index.tsx」に「import ‘bootstrap/dist/css/bootstrap.min.css’;」を追加します。

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css'; // BootstrapのCSSをインポート

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

フォルダ構成を整える

次にフォルダ構成を少し整理します。
今回作成する予定のファイルを予め作っておくと良いかなと思いますので、下記のような構成にしてください。

react-app
├── node_modules
├── public
├── src
│   ├── App.css
│   ├── App.tsx
│   ├── components:新規作成
│   │   └── calculator:新規作成
│   │       ├── CalculatorForm.tsx:新規作成
│   │       └── ResultDisplay.tsx:新規作成
│   ├── index.css
│   ├── index.tsx
│   ├── pages:新規作成
│   │   └── CalculatorPage.tsx:新規作成
│   └── react-app-env.d.ts
├── package-lock.json
├── package.json
├── README.md
└── tsconfig.json

四則演算UIをBootstrapで作っていく

枠を作成

では、さっそく四則演算のUIをBootstrapで作成していきます。
まずは、フォームは作らずに枠だけ作成してみます。

画像の赤枠の部分を作るコンポーネントは、CaluculatorPage.tsxになります。
まずは、「pages > CalculatorPage.tsx」を開きます。

import React, { useState } from 'react';
import { Container, Row, Col, Card } from 'react-bootstrap';

const CalculatorPage: React.FC = () => {
    return (
        <Container className="mt-5">
            <Row className="justify-content-center">
                <Col md={6}>
                    <Card>
                        <Card.Header>四則演算</Card.Header>
                        <Card.Body>
                            ここに四則演算用フォームを作っていく
                        </Card.Body>
                    </Card>
                </Col>
            </Row>
        </Container>
    );
};

export default CalculatorPage;

Bootstrapの下記を利用しています。使い方がわからないものは、調べるようにしておきましょう。

  • Container
  • Row
  • Card
  • Card.Header
  • Card.Body

次に、「App.tsx」でCalculatorPageをインポートして、表示してみます。

import './App.css';
import CalculatorPage from './pages/CalculatorPage';

function App() {
  return (
    <div className="App">
      <CalculatorPage />
    </div>
  );
}

export default App;

これで、とりあえず枠が作成できました。

フォームを作成

次に、数値1や演算子などを入力する四則演算フォームを作成していきます。

四則演算フォームは、「components > calculator > CalculatorForm.tsx」で定義します。
handleCalculateは、四則演算の処理を入れていますが、FastAPIでAPIを作成したらここの処理は書き換えます。

import React, { useState } from 'react';
import { Form, Button } from 'react-bootstrap';

interface CalculatorFormProps {
    onCalculate: (result: number | string) => void;
}

const CalculatorForm: React.FC<CalculatorFormProps> = ({ onCalculate }) => {
    const [num1, setNum1] = useState<number | ''>('');
    const [num2, setNum2] = useState<number | ''>('');
    const [operator, setOperator] = useState<string>('+');

    // ※今後FastAPIにリクエストする処理に書き換える
    const handleCalculate = () => {
        const a = typeof num1 === 'number' ? num1 : parseFloat(num1);
        const b = typeof num2 === 'number' ? num2 : parseFloat(num2);
        let res: number | string;

        switch (operator) {
            case '+':
                res = a + b;
                break;
            case '-':
                res = a - b;
                break;
            case '*':
                res = a * b;
                break;
            case '/':
                res = b !== 0 ? a / b : 'Error: Division by zero';
                break;
            default:
                res = 0;
        }
        onCalculate(res);
    };

    return (
        <Form>
            <Form.Group controlId="num1">
                <Form.Label>数値1</Form.Label>
                <Form.Control
                    type="number"
                    value={num1}
                    onChange={(e) => setNum1(e.target.value === '' ? '' : parseFloat(e.target.value))}
                />
            </Form.Group>

            <Form.Group controlId="operator" className="mt-3">
                <Form.Label>演算子</Form.Label>
                <Form.Control
                    as="select"
                    value={operator}
                    onChange={(e) => setOperator(e.target.value)}
                >
                    <option value="+">+</option>
                    <option value="-">-</option>
                    <option value="*">*</option>
                    <option value="/">/</option>
                </Form.Control>
            </Form.Group>

            <Form.Group controlId="num2" className="mt-3">
                <Form.Label>数値2</Form.Label>
                <Form.Control
                    type="number"
                    value={num2}
                    onChange={(e) => setNum2(e.target.value === '' ? '' : parseFloat(e.target.value))}
                />
            </Form.Group>

            <Button variant="primary" className="mt-4" onClick={handleCalculate}>
                計算
            </Button>
        </Form>
    );
};

export default CalculatorForm;

覚えるべきポイント

  • useState
  • Form
  • Button

CalculatorFormは、CalculatorPageで利用しますので、下記のように書き換えてみましょう。

import React, { useState } from 'react';
import { Container, Row, Col, Card } from 'react-bootstrap';
import CalculatorForm from '../components/calculator/CalculatorForm'; // CalculatorFormをインポート

const CalculatorPage: React.FC = () => {
    const [result, setResult] = useState<number | string | null>(null);

    // 計算結果をresultに保存
    const handleCalculate = (calculatedResult: number | string) => {
        setResult(calculatedResult);
    };

    return (
        <Container className="mt-5">
            <Row className="justify-content-center">
                <Col md={6}>
                    <Card>
                        <Card.Header>四則演算</Card.Header>
                        <Card.Body>
                            <CalculatorForm onCalculate={handleCalculate} />
                        </Card.Body>
                    </Card>
                </Col>
            </Row>
        </Container>
    );
};

export default CalculatorPage;

覚えるべきポイント

  • const [result, setResult] = useState(null);:result:結果が格納される、setResult:結果を格納するための関数
  • onCalculate={handleCalculate}:ここでhandleCalculateを渡している

下記のような画面になったと思います。
ボタンを押しても、まだ何も起こらないことを確認しておいてください。

結果を表示

では、resultを受け取って、結果を表示するコンポーネントを作りましょう。
下記の部分になります。

結果を表示するコンポーネントは、「components > calculator > ResultDisplay.tsx」で定義していきます。

import React from 'react';
import { Card } from 'react-bootstrap';

interface ResultDisplayProps {
    result: number | string | null;
}

const ResultDisplay: React.FC<ResultDisplayProps> = ({ result }) => {
    return result !== null ? (
        <Card.Text className="mt-3">
            結果: <strong>{result}</strong>
        </Card.Text>
    ) : null;
};

export default ResultDisplay;

結果も「CalculatorPage」で利用しますので、インポートしていきます。

import React, { useState } from 'react';
import { Container, Row, Col, Card } from 'react-bootstrap';
import CalculatorForm from '../components/calculator/CalculatorForm'; // CalculatorFormをインポート
import ResultDisplay from '../components/calculator/ResultDisplay';// ResultDisplayをインポート

const CalculatorPage: React.FC = () => {
    // 計算結果
    const [result, setResult] = useState<number | string | null>(null);

    // 計算結果をresultに保存
    const handleCalculate = (calculatedResult: number | string) => {
        setResult(calculatedResult);
    };

    return (
        <Container className="mt-5">
            <Row className="justify-content-center">
                <Col md={6}>
                    <Card>
                        <Card.Header>四則演算</Card.Header>
                        <Card.Body>
                            <CalculatorForm onCalculate={handleCalculate} />
                            <ResultDisplay result={result} />
                        </Card.Body>
                    </Card>
                </Col>
            </Row>
        </Container>
    );
};

export default CalculatorPage;

画面を確認すると、無事結果が表示されると思います。
これで四則演算UIの作成は、完了です!

Python(FastAPI)で四則演算APIを作る

先ほど、Reactで四則演算のUIを作成しましたので、次はPython(FastAPI)を利用して、四則演算APIを作成します。

事前準備

事前準備として、仮想環境の構築や、必要なライブラリ等をインストールしていきましょう。

venv

venvを利用することで、仮想環境を作ることができます。
詳しくは説明を省きますが、複数のバージョンを使えたりとメリットがあります。

$ sudo apt install python3.12-venv
$ python3 -m venv venv
$ source venv/bin/activate // Windows:venv\Scripts\activate
(venv) ****$ 

(venv)という表記が出ていればOKです。

ライブラリ類

pipを利用して、ライブラリ類をインストールします。

$ pip install fastapi uvicorn
$ pip install pydantic-settings
  • fastapi
  • uvicorn
  • pydantic-settings

requirements.txtをfreezeを利用して生成しておきましょう。

$ pip freeze > requirements.txt // requirements.txtファイルを作成し、インストールしたパッケージを記録
annotated-types==0.7.0
anyio==4.6.2.post1
click==8.1.7
fastapi==0.115.5
h11==0.14.0
idna==3.10
pydantic==2.9.2
pydantic_core==2.23.4
sniffio==1.3.1
starlette==0.41.2
typing_extensions==4.12.2
uvicorn==0.32.0

フォルダ構成を整える

ここまで出来たら、フォルダ構成をいったん整えておきましょう。

fastapi-app
├── app:新規作成
│   ├── api:新規作成
│   │   ├── __init__.py:新規作成
│   │   ├── calculator.py:新規作成
│   │   └── hello.py:新規作成
│   ├── services:新規作成
│   │   └── calculator_service.py:新規作成
│   ├── main.py:新規作成
│   └── config.py:新規作成
├── requirements.txt
└── README.md:新規作成

アプリ設定値を管理する

「config.py」でアプリ共通の設定値などを管理しておきます。

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    APP_NAME: str = "Simple FastAPI App"
    DEBUG: bool = True

settings = Settings()

Hello World!!を返却するAPIを作ってみる

四則演算APIを作る前に、Hello World!!を返却するAPIを作ってみます。

「hello.py」に下記を記述します。

from fastapi import APIRouter
router = APIRouter()

@router.get("/hello")
def hello():
    result = "Hello World!!"
    return {"result": result}
  • @router.get(“/hello”):GETで/helloをエンドポイントにリクエストするとルーティングされる

次に「main.py」に下記を記述します。

from fastapi import FastAPI, APIRouter
from fastapi.middleware.cors import CORSMiddleware
from app.api import hello
from app.config import settings

app = FastAPI(title=settings.APP_NAME)

# 全オリジンを許可するCORS設定
# ※開発都合上、全許可で設定しています。商用等では適切な設定にしてください。
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # すべてのオリジンを許可
    allow_credentials=True,
    allow_methods=["*"],  # 全てのHTTPメソッドを許可
    allow_headers=["*"],  # 全てのヘッダーを許可
)

# 共通のprefixを持つメインルーターを作成
main_router = APIRouter(prefix="/api")

# 各サブルーターをメインルーターに追加
main_router.include_router(hello.router)

# アプリケーションにメインルーターを追加
app.include_router(main_router)
  • app.add_middleware:難しいので記述してもらえればOKです。(商用などの場合は、設定を適切に)
  • main_router = APIRouter(prefix=”/api”):エンドポイントを共通で「/api/xxx」とします
  • main_router.include_router(hello.router):ルーターにhelloを追加します

ここまでできたら、下記のコマンドでアプリを実行してみます。

$ uvicorn app.main:app --reload

ブラウザで「http://localhost:8000/api/hello」を確認してみると、下記のような画面が出てくると思います。

四則演算APIを作ってみる

要領はつかめたかと思いますので、四則演算APIを作ってみます。

まずは、「services > calculator_service.py」に四則演算のロジックを記載していきます。
servicesには、ビジネスロジックと言って処理のロジックを記載していくことが多いです。

class CalculatorService:
    def perform_operation(self, num1: float, num2: float, operator: str) -> float:
        if operator == '+':
            return num1 + num2
        elif operator == '-':
            return num1 - num2
        elif operator == '*':
            return num1 * num2
        elif operator == '/':
            if num2 == 0:
                raise ValueError("Division by zero is not allowed")
            return num1 / num2
        else:
            raise ValueError("Invalid operator")

次に、helloと同様に「api > calculator.py」にリクエストを受けて、レスポンスを返却する処理を作りましょう。

from fastapi import APIRouter, Depends, HTTPException
from app.services.calculator_service import CalculatorService

router = APIRouter()

@router.get("/calculate")
def calculate(num1: float, num2: float, operator: str, service: CalculatorService = Depends()):
    try:
        result = service.perform_operation(num1, num2, operator)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    return {"num1": num1, "num2": num2, "operator": operator, "result": result}

では、ルーターに追加するために「main.py」を編集します。

from fastapi import FastAPI, APIRouter
from fastapi.middleware.cors import CORSMiddleware
from app.api import hello, calculator
from app.config import settings

app = FastAPI(title=settings.APP_NAME)

# 全オリジンを許可するCORS設定
# ※開発都合上、全許可で設定しています。商用等では適切な設定にしてください。
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # すべてのオリジンを許可
    allow_credentials=True,
    allow_methods=["*"],  # 全てのHTTPメソッドを許可
    allow_headers=["*"],  # 全てのヘッダーを許可
)

# 共通のprefixを持つメインルーターを作成
main_router = APIRouter(prefix="/api")

# 各サブルーターをメインルーターに追加
main_router.include_router(hello.router)
main_router.include_router(calculator.router)

# アプリケーションにメインルーターを追加
app.include_router(main_router)

これで、四則演算APIができているはずです。
ブラウザで下記を表示してみましょう。同じ結果になれば、問題ないです。

http://localhost:8000/api/calculate?num1=3&num2=3&operator=add

{"num1":3.0,"num2":3.0,"operator":"add","result":6.0}
http://localhost:8000/api/calculate?num1=3&num2=3&operator=subtract

{"num1":3.0,"num2":3.0,"operator":"subtract","result":0.0}
http://localhost:8000/api/calculate?num1=3&num2=3&operator=multiply

{"num1":3.0,"num2":3.0,"operator":"multiply","result":9.0}
http://localhost:8000/api/calculate?num1=3&num2=3&operator=divide

{"num1":3.0,"num2":3.0,"operator":"divide","result":1.0}

ReactとPython(FastAPI)を連携させる

これでReactのUIとPython(FastAPI)のAPIが完成したので、次は連携させていきます。
React側の修正になります。

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

最初に、「axios」というライブラリをインストールします。

$ npm install axios
  • axios:axiosとはHTTP通信(データの更新・取得)を簡単に行うことができるJavaScriptのライブラリ

handleCalculateを書き換える

計算ボタンを押下した際に呼び出される「handleCalculate」に四則演算の処理を書いていましたが、これをPython(FastAPI)のAPIにリクエストして結果をもらう処理に書き換えます。

「components > calculator > CalculatorForm.tsx」を下記に書き換えます。

import React, { useState } from 'react';
import axios from 'axios';
import { Form, Button } from 'react-bootstrap';

interface CalculatorFormProps {
    onCalculate: (result: number | string) => void;
}

const CalculatorForm: React.FC<CalculatorFormProps> = ({ onCalculate }) => {
    const [num1, setNum1] = useState<number | ''>('');
    const [num2, setNum2] = useState<number | ''>('');
    const [operator, setOperator] = useState<string>('+');
    const [error, setError] = useState<string | null>(null);

    // 記号を文字列にマッピング
    const operatorMap: { [key: string]: string } = {
        '+': 'add',
        '-': 'subtract',
        '*': 'multiply',
        '/': 'divide'
    };

    const handleCalculate = async () => {
        setError(null); // 計算するたびに、一度エラーは初期化
        try {
            const response = await axios.get('http://localhost:8000/api/calculate', {
                params: {
                    num1,
                    num2,
                    operator: operatorMap[operator]  // マッピングされた演算子に置き換える
                }
            });
            onCalculate(response.data.result);
        } catch (err) {
            // APIで何かエラーが発生した場合
            setError("計算エラーが発生しました");
        }
    };

    return (
        <Form>
            <Form.Group controlId="num1">
                <Form.Label>数値1</Form.Label>
                <Form.Control
                    type="number"
                    value={num1}
                    onChange={(e) => setNum1(e.target.value === '' ? '' : parseFloat(e.target.value))}
                />
            </Form.Group>

            <Form.Group controlId="operator" className="mt-3">
                <Form.Label>演算子</Form.Label>
                <Form.Control
                    as="select"
                    value={operator}
                    onChange={(e) => setOperator(e.target.value)}
                >
                    <option value="+">+</option>
                    <option value="-">-</option>
                    <option value="*">*</option>
                    <option value="/">/</option>
                </Form.Control>
            </Form.Group>

            <Form.Group controlId="num2" className="mt-3">
                <Form.Label>数値2</Form.Label>
                <Form.Control
                    type="number"
                    value={num2}
                    onChange={(e) => setNum2(e.target.value === '' ? '' : parseFloat(e.target.value))}
                />
            </Form.Group>

            <Button variant="primary" className="mt-4" onClick={handleCalculate}>
                計算
            </Button>
            {error && <div style={{ color: 'red', marginTop: '10px' }}>{error}</div>}
        </Form>
    );
};

export default CalculatorForm;
  • const response = await axios.get(‘http://localhost:8000/api/calculate’, {
    →axiosを使って、GETで[http://localhost:8000/api/calculate]にリクエストを送っています。
    // 記号を文字列にマッピング
    const operatorMap: { [key: string]: string } = {
        '+': 'add',
        '-': 'subtract',
        '*': 'multiply',
        '/': 'divide'
    };

こちらの処理は、APIのoperatorパラメータと一致させるための処理になります。
+を選ぶと、addが取得できます。

完成!

これで完成になります。
ReactとPythonのアプリを両方起動して、「http://localhost:3000」をブラウザで表示してみましょう。

Python(FastAPI)にリクエストを送り、Python側で計算をした上で、Reactに返却し、結果が表示されているかと思います!

最後に

今回は、ReactとPython(FastAPI)を利用した四則演算アプリを作成してみました!
DBを使っていないため、大規模なアプリを作ったりはできませんが、簡単なアプリならこの要領で作れると思います。

ぜひ参考にしてみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

クラウド関連を勉強するために始めたブログです。
未経験の技術のため、広い心を持って見ていただけると嬉しく思います。
情報セキュリティを勉強するために、「Hack Lab. 256」もあります。
情報セキュリティに興味がある方は、ぜひ覗いて見てください!

目次