Build A Full-Stack App: FastAPI, React & MySQL
Build a Full-Stack App: FastAPI, React & MySQL
Hey everyone! Today, we’re diving into a super cool project: building a full-stack application using FastAPI for our backend, React for our frontend, and MySQL for our database. This combination is a powerful one, and by the end of this article, you’ll have a solid understanding of how these technologies work together and how to build your own awesome apps. Let’s get started, shall we?
Table of Contents
- Setting Up Your Development Environment
- Python and FastAPI Installation
- React Setup
- MySQL Setup
- Building the FastAPI Backend
- Project Structure
- Coding the Backend
- Building the React Frontend
- Project Structure
- Coding the Frontend
- Connecting Frontend and Backend
- API Calls with Axios
- CORS Configuration
- Testing the Connection
- Advanced Features and Enhancements
- User Authentication
- Database Relationships
- Pagination and Filtering
- Deployment
- Conclusion
Setting Up Your Development Environment
Before we jump into the code, we need to make sure we’ve got our development environment set up. Don’t worry, it’s not as scary as it sounds! We’ll go step-by-step. First things first, you’ll need to have Python installed. FastAPI is built on Python, so that’s a must. Make sure you have the latest stable version. Next, we’re going to use Node.js and npm or yarn to handle our React project. These are essential for managing your frontend dependencies. Finally, you’ll need a MySQL database. You can either install it locally or use a cloud-based service like AWS RDS or Google Cloud SQL . I recommend a local setup, it’s easier to get started.
Python and FastAPI Installation
Okay, let’s get our hands dirty with some code. Create a new directory for your project and navigate into it using your terminal. We will create a virtual environment to keep our dependencies clean and isolated. Run
python -m venv .venv
to create the virtual environment and
source .venv/bin/activate
to activate it (on macOS and Linux) or
.venvinash
(on Windows). Then, install
FastAPI
and
Uvicorn
(an ASGI server, which FastAPI uses) using pip:
pip install fastapi uvicorn
. We’ll also need some extra libraries like
pydantic
for data validation, and
SQLAlchemy
for interacting with the database. You can install them with
pip install pydantic sqlalchemy mysql-connector-python
. We are also using
mysql-connector-python
to connect our database and Python.
React Setup
Now, let’s switch gears and set up our React frontend. Inside the project directory (or a subdirectory, if you prefer to keep the frontend and backend separate), use
npx create-react-app frontend
to scaffold a new React app. This command sets up a basic React project with all the necessary files and configurations. Once the installation is complete, navigate into the
frontend
directory and start the development server using
npm start
or
yarn start
. This will open your React app in your browser, usually at
http://localhost:3000
. At this moment, your React frontend should be running. Let’s move onto the database.
MySQL Setup
Next up, setting up MySQL. If you are using a local installation, make sure the MySQL server is running. You can connect to your MySQL database using a client like
MySQL Workbench
or through the command line. Create a new database for your application. This is where your data will be stored. You can use any name you like, but keep it simple, like
my_app_db
. Then, create a database user and grant it the necessary privileges. This is crucial for security. Make sure to choose a strong password and restrict the user’s access to only the
my_app_db
database. Now we have finished all the set-ups needed for building our first app, let’s start with the Backend part.
Building the FastAPI Backend
Alright, let’s build the heart of our application: the FastAPI backend! This is where we’ll handle API endpoints, data validation, and interactions with the database. We will start with a basic structure and gradually add features. The backend will interact with MySQL.
Project Structure
Create the following structure for your FastAPI backend:
my_app/
├── main.py
├── models.py
├── database.py
├── schemas.py
└── .env (optional)
-
main.py: This is the main entry point of your application. It contains the API endpoints and connects everything together. -
models.py: Defines the database models using SQLAlchemy . These models represent the structure of your data in the database. -
database.py: Contains the database connection and session management code. -
schemas.py: Defines the data schemas using Pydantic . These schemas are used for data validation and serialization. -
.env(optional): This file stores environment variables, such as database credentials, that should not be hardcoded in your code.
Coding the Backend
Let’s start coding. First, in
database.py
, we’ll set up the database connection:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os
# Retrieve database credentials from environment variables
DB_USER = os.environ.get("DB_USER")
DB_PASSWORD = os.environ.get("DB_PASSWORD")
DB_HOST = os.environ.get("DB_HOST")
DB_NAME = os.environ.get("DB_NAME")
# Construct the database URL
DATABASE_URL = f"mysql+mysqlconnector://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
Next, in
models.py
, we define our database model (e.g., a
Todo
model):
from sqlalchemy import Column, Integer, String
from database import Base
class Todo(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String)
description = Column(String, default="")
In
schemas.py
, we define the Pydantic schemas:
from pydantic import BaseModel
class TodoBase(BaseModel):
title: str
description: str = ""
class TodoCreate(TodoBase):
pass
class Todo(TodoBase):
id: int
class Config:
orm_mode = True
Finally, in
main.py
, we create the API endpoints:
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import models, schemas, database
app = FastAPI()
# Dependency to get the database session
def get_db():
db = database.SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/todos/", response_model=schemas.Todo)
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
db_todo = models.Todo(**todo.dict())
db.add(db_todo)
db.commit()
db.refresh(db_todo)
return db_todo
@app.get("/todos/", response_model=list[schemas.Todo])
def read_todos(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
todos = db.query(models.Todo).offset(skip).limit(limit).all()
return todos
Run the backend using
uvicorn main:app --reload
. This command starts the FastAPI server. Now, we’re ready to build the frontend part.
Building the React Frontend
Now, let’s build the React frontend! This is where users will interact with your application. We’ll create components to display data, handle user input, and make API calls to the backend. We’ll be using Axios , a popular library for making HTTP requests in the frontend.
Project Structure
Inside the
frontend
directory (created by
create-react-app
), the project structure is typically as follows:
frontend/
├── src/
│ ├── App.js
│ ├── components/
│ │ ├── TodoList.js
│ │ ├── TodoForm.js
│ ├── services/
│ │ ├── api.js
│ ├── App.css
│ └── index.js
├── public/
├── package.json
└── ...
-
App.js: The main component of your application. It usually handles routing and overall layout. -
components/: Contains reusable UI components, such asTodoListandTodoForm. -
services/: Contains API service functions, such asapi.js, for making requests to the backend. -
App.css: Contains the CSS styles for your application. -
index.js: The entry point of your React application.
Coding the Frontend
Let’s write some code! First, install Axios:
npm install axios
within the
frontend
directory. Next, we are going to create a service to connect to our backend.
In
services/api.js
:
import axios from 'axios';
const API_URL = 'http://localhost:8000'; // Replace with your backend URL
const api = axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
},
});
export const getTodos = () => api.get('/todos/');
export const createTodo = (todo) => api.post('/todos/', todo);
export default api;
Then, let’s create a
TodoList
component (
components/TodoList.js
) to display the todo items:
import React, { useState, useEffect } from 'react';
import api from '../services/api';
function TodoList() {
const [todos, setTodos] = useState([]);
useEffect(() => {
const fetchTodos = async () => {
try {
const response = await api.getTodos();
setTodos(response.data);
} catch (error) {
console.error('Error fetching todos:', error);
}
};
fetchTodos();
}, []);
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
export default TodoList;
And a
TodoForm
component (
components/TodoForm.js
) for adding new todos:
import React, { useState } from 'react';
import api from '../services/api';
function TodoForm() {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
await api.createTodo({ title, description });
setTitle('');
setDescription('');
// Optionally refresh the todo list
} catch (error) {
console.error('Error creating todo:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Title"
/>
<input
type="text"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Description"
/>
<button type="submit">Add Todo</button>
</form>
);
}
export default TodoForm;
Finally, update
App.js
to render these components:
import React from 'react';
import TodoList from './components/TodoList';
import TodoForm from './components/TodoForm';
function App() {
return (
<div>
<h1>Todo App</h1>
<TodoForm />
<TodoList />
</div>
);
}
export default App;
Now, run your React app with
npm start
in the
frontend
directory. Your frontend should now display a list of todos and a form to add new ones. We’ve built the frontend part, let’s look into the database part.
Connecting Frontend and Backend
Alright, let’s connect our Frontend and Backend ! We’ve already set up the API endpoints in FastAPI and created the UI components in React, so let’s tie them together. We’ll do this by making API calls from our React components to our FastAPI backend.
API Calls with Axios
In your React frontend, we will make use of
Axios
(if you didn’t install, use
npm install axios
or
yarn add axios
to install it.) to make HTTP requests to the FastAPI backend. You already have created
api.js
in the previous step.
CORS Configuration
To allow your React frontend (running on a different port than your FastAPI backend) to make requests to the backend, you’ll need to configure
CORS
(Cross-Origin Resource Sharing). Install the
python-cors
package in your FastAPI backend:
pip install python-cors
. Then, add the following to your
main.py
:
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost:3000", # Replace with your frontend's URL
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
This configuration allows requests from your React frontend (running on
http://localhost:3000
) to access your backend.
Testing the Connection
Run both your frontend and backend. You should now be able to add new todos through the frontend. When you add a new todo, the frontend makes a POST request to the backend. The backend saves the todo to the database, and then the frontend fetches the updated list of todos. When you refresh the page or restart the React App, all the information you saved will be still there. Your frontend is now successfully communicating with the backend!
Advanced Features and Enhancements
Congrats on building a full-stack app! Let’s explore some cool features to make your app even better. We’ll cover topics that can take your project to the next level.
User Authentication
Implementing user authentication is a must for most real-world applications.
FastAPI
integrates well with libraries like
passlib
for password hashing and
JWT (JSON Web Tokens)
for user authentication. You can create endpoints for user registration, login, and authorization to secure your API and manage user access.
Database Relationships
For more complex applications, you might need to define relationships between your database tables. SQLAlchemy supports various relationship types, such as one-to-many and many-to-many. For instance, in a blog application, you might have a one-to-many relationship between users and posts, or a many-to-many relationship between posts and tags.
Pagination and Filtering
When dealing with large datasets, it’s essential to implement pagination to improve performance and user experience. Use the
skip
and
limit
parameters in your API endpoints to paginate your data. Also, enable filtering and sorting to let users easily find what they’re looking for. Libraries like
SQLAlchemy
make it easy to filter data based on various criteria.
Deployment
Once your app is ready, deploy it so others can use it! Deploying the backend can be done with Docker and a cloud platform like AWS , Google Cloud , or Heroku . Deploying the frontend involves using services like Netlify or Vercel , which provides easy deployment and hosting for React applications.
Conclusion
That’s a wrap, folks! You’ve learned how to build a full-stack application using FastAPI , React , and MySQL . We covered setting up the development environment, building the backend, creating the frontend, connecting them, and implementing advanced features. Now, go out there and build something amazing! Remember to have fun and enjoy the process of learning and creating. Happy coding! If you’re interested in going further, you can check more documentations from the official documentation from FastAPI , React and MySQL . Good luck!