Create a project
① Create React and FastAPI folders
python3 -m venv env
source env/bin/activate
pip install fastapi uvicorn sqlalchemy
② Create database.py and main.py, models.py for FastAPI folders
FastAPI/database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
URL_DATABASE = 'sqlite:///./finance.db'
engine = create_engine(URL_DATABASE, connect_args={"check_same_thread": False})
SessionLoacal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
FastAPI/models.py
from database import Base
from sqlalchemy import Column, Integer, String, Boolean, Float
class Transaction(Base):
__tablename__ = 'transactions'
id = Column(Integer, primary_key=True, index=True)
amount = Column(Float)
category = Column(String)
description = Column(String)
is_income = Column(Boolean)
date = Column(String)
FastAPI/main.py
from fastapi import FastAPI, HTTPException, Depends
from typing import Annotated
from sqlalchemy.orm import Session
from pydantic import BaseModel
from database import SessionLoacal, engine
import models
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
'http://localhost:3000'
]
app.add_middleware(
CORSMiddleware,
add_origins=origins,
)
class TransactionBase(BaseModel):
amount: float
category: str
description: str
is_income: bool
date: str
class TransactionModel(TransactionBase):
id: int
class Config:
orm_mode = True
def get_db():
db = SessionLoacal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
models.Base.metadata.create_all(bind=engine)
@app.post("/transactions/", response_model=TransactionModel)
async def create_transaction(transaction: TransactionBase, db: db_dependency):
db_transaction = models.Transaction(**transaction.dict())
db.add(db_transaction)
db.commit()
db.refresh(db_transaction)
return db_transaction
@app.get("/transactions", response_model=List[TransactionModel])
async def read_transactions(db: db_dependency, skip: int = 0, limit: int = 100):
transactions = db.query(models.Transaction).offset(skip).limit(limit).all()
return transactions
cd FastAPI
uvicorn main:app --reload
npx install axios
③ Create React
cd React
npx create-react-app <プロジェクト>
④Paste the Boostrap code in public/index.html
public/index.html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
//省略
<body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
⑤Edit App.js
App.js
import React, { useState, useEffect } from 'react';
import api from './api';
const App = () => {
const [transactions, setTransactions] = useState([]);
const [formData, setFormData] = useState({
amount: '',
category: '',
description: '',
is_income: false,
date: '',
});
const fetchTransactions = async () => {
const response = await api.get('/transaction/');
setTransactions(response.data);
};
useEffect(() => {
fetchTransactions();
}, []);
const handleInputChange = (event) => {
const value =
event.target.type === 'checkbox'
? event.target.checked
: event.target.value;
setFormData({
...formData,
[event.target.name]: value,
});
};
const handleFormSubmit = async (event) => {
event.preventDefault();
await api.post('/transactions/', formData);
fetchTransactions();
setFormData({
amount: '',
category: '',
description: '',
is_income: false,
date: '',
});
};
return (
<div>
<nav className='navbar navbar-dark bg-primary'>
<div className='container-fluid'>
<a className='navbar-brand' href='https://www.example.com/'>
Finance app
</a>
</div>
</nav>
<div className='container'>
<form onSubmit={handleFormSubmit}>
<div className='mb-3 mt-3'>
<label htmlFor='amount' className='form-label'>
Amount
</label>
<input
type='text'
className='form-control'
id='amount'
name='amount'
onChange={handleInputChange}
value={formData.amount}
/>
</div>
<div className='mb-3'>
<label htmlFor='category' className='form-label'>
Category
</label>
<input
type='text'
className='form-control'
id='category'
name='category'
onChange={handleInputChange}
value={formData.category}
/>
</div>
<div className='mb-3'>
<label htmlFor='description' className='form-label'>
Description
</label>
<input
type='text'
className='form-control'
id='description'
name='description'
onChange={handleInputChange}
value={formData.description}
/>
</div>
<div className='mb-3'>
<label htmlFor='is_income' className='form-label'>
Income?
</label>
<input
type='text'
id='is_income'
name='is_income'
onChange={handleInputChange}
value={formData.is_income}
/>
</div>
<div className='mb-3'>
<label htmlFor='date' className='form-label'>
Date
</label>
<input
type='text'
id='date'
name='date'
onChange={handleInputChange}
value={formData.date}
/>
</div>
<button type='submit' className='btn btn-primary'>
Submit
</button>
</form>
<table className='table table-striped table-bordered table-hover'>
<thead>
<tr>
<th>Amount</th>
<th>Category</th>
<th>Description</th>
<th>Income</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{transactions.map((transaction) => (
<tr key={transaction.id}>
<td>{transaction.amount}</td>
<td>{transaction.category}</td>
<td>{transaction.description}</td>
<td>{transaction.is_income ? 'Yes' : 'No'}</td>
<td>{transaction.data}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
export default App;
⑥Create api.js
api.js
import axios from 'axios';
const api = axios.create({
baseURL: 'http://loaclhost:8000',
});
export default api;
⑦ Edit main.py
main.py
from fastapi import FastAPI, HTTPException, Depends
from typing import Annotated, List
from sqlalchemy.orm import Session
from pydantic import BaseModel
from database import SessionLoacal, engine
import models
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=['*']
)
class TransactionBase(BaseModel):
amount: float
category: str
description: str
is_income: bool
date: str
class TransactionModel(TransactionBase):
id: int
class Config:
orm_mode = True
def get_db():
db = SessionLoacal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
models.Base.metadata.create_all(bind=engine)
@app.post("/transactions/", response_model=TransactionModel)
async def create_transaction(transaction: TransactionBase, db: db_dependency):
db_transaction = models.Transaction(**transaction.dict())
db.add(db_transaction)
db.commit()
db.refresh(db_transaction)
return db_transaction
@app.get("/transactions/", response_model=List[TransactionModel])
async def read_transactions(db: db_dependency, skip: int = 0, limit: int = 100):
transactions = db.query(models.Transaction).offset(skip).limit(limit).all()
return transactions
Reference site
How to build a React + FastAPI application (Full Stack Guide)