Getting started with React, Tailwindcss, Node.js, Flask and MongoDB
Tail'ed
Posted on March 13, 2024
Workshop Explanation: Building a Full Stack Application with React and Flask
In this workshop, we will guide you through building a full-stack web application using React for the frontend and Flask for the backend. The application will involve basic CRUD (Create, Read, Update, Delete) operations on user data, with MongoDB as the database.
Prerequisites
Before we begin, ensure you have the following installed:
- Node.js
- Python 3
- Docker
Step 1: Setting Up the Project Structure
Let's start by creating the project directory and setting up the initial structure.
mkdir react-flask-tutorial
cd react-flask-tutorial
Step 2: Creating React Frontend
We'll begin by creating the frontend using Create React App.
npx create-react-app client
cd client
npm start
This sets up a basic React application. You can start the development server by running npm start
.
Step 3: Setting Up Flask Backend
Now, let's create the Flask backend.
mkdir server
cd server
python3 -m venv .venv
. .venv/Scripts/activate
pip install Flask
touch hello.py
Inside hello.py
, we define a basic Flask route:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
Run the Flask app using:
flask --app hello run
You can access the Flask app at http://localhost:5000/
.
Step 4: Linking Frontend and Backend
To enable communication between the frontend and backend, we'll install and configure Flask-CORS.
pip install flask-cors
Now, we update hello.py
to include CORS support and an additional route for receiving POST requests:
from flask import Flask, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route("/hello", methods=["POST"])
def hello():
data = request.get_json()
return {"hello": data["name"]}
Step 5: Implementing CRUD Operations with MongoDB
We'll integrate MongoDB for database operations. Ensure you have Docker installed, then run a MongoDB container:
docker run --env=HOME=/data/db --volume=~/workspace/tailed/workshop/react-flask-tutorial/db:/data/db --volume=/data/configdb --volume=/data/db -p 27017:27017 -d mongo:latest
Install pymongo
for Python MongoDB interaction:
pip install pymongo
In hello.py
, we define routes for CRUD operations on user data.
import datetime
import json
from bson import ObjectId
from flask import Flask, request
from flask.json.provider import JSONProvider
from flask_cors import CORS
from pymongo import MongoClient
# Custom JSON Encoder to handle ObjectId and datetime
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
if isinstance(o, datetime.datetime):
return str(o)
return json.JSONEncoder.default(self, o)
# Custom JSON Provider to use the custom encoder
class CustomJSONProvider(JSONProvider):
def dumps(self, obj, **kwargs):
return json.dumps(obj, **kwargs, cls=JSONEncoder)
def loads(self, s: str | bytes, **kwargs):
return json.loads(s, **kwargs)
app = Flask(__name__)
CORS(app)
# Set custom JSON provider
app.json = CustomJSONProvider(app)
# Connect to MongoDB
def get_database():
CONNECTION_STRING = "mongodb://localhost:27017/"
client = MongoClient(CONNECTION_STRING)
return client['demo']
dbname = get_database()
collection_name = dbname["users"]
# Routes for CRUD operations
@app.route("/users", methods=["GET"])
def get_users():
users = list(collection_name.find())
return users
@app.route("/users", methods=["POST"])
def create_user():
data = request.get_json()
user = collection_name.insert_one(data)
data["_id"] = user.inserted_id
return data
@app.route("/users/<id>", methods=["DELETE"])
def delete_user(id):
collection_name.delete_one({"_id": ObjectId(id)})
return {"message": "User deleted"}
@app.route("/users/<id>", methods=["PUT"])
def update_user(id):
data = request.get_json()
collection_name.update_one({"_id": ObjectId(id)}, {"$set": data})
data["_id"] = id
return data
Here are the equivalent curl
commands for each of the CRUD operations:
GET Request to Retrieve Users:
curl -X GET http://localhost:5000/users
POST Request to Create a User:
curl -X POST -H "Content-Type: application/json" -d '{"name": "John", "age": 30}' http://localhost:5000/users
Replace {"name": "John", "age": 30}
with the JSON data you want to insert.
DELETE Request to Delete a User by ID:
curl -X DELETE http://localhost:5000/users/INSERT_ID_HERE
Replace INSERT_ID_HERE
with the ID of the user you want to delete.
PUT Request to Update a User by ID:
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Updated Name", "age": 40}' http://localhost:5000/users/INSERT_ID_HERE
Replace {"name": "Updated Name", "age": 40}
with the updated JSON data, and INSERT_ID_HERE
with the ID of the user you want to update.
Step 6: Styling with Tailwind CSS
We'll use Tailwind CSS for styling. Install Tailwind CSS and create a configuration file:
npm install -D tailwindcss
npx tailwindcss init
Modify the tailwind.config.js
file:
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
plugins: [],
}
Include Tailwind CSS in your project's CSS file (App.css
):
@tailwind base;
@tailwind components;
@tailwind utilities;
Update the frontend React components to utilize Tailwind CSS classes for styling.
// container className={"bg-zinc-800 min-h-[100vh] flex flex-col items-center justify-center gap-5 text-white"}
// button green className={"bg-green-700 hover:bg-green-800 rounded p-2"}
// button red className={"bg-red-500 hover:bg-red-600 rounded p-2"}
// button blue className={"bg-blue-500 hover:bg-blue-600 rounded p-2"}
// li className={"flex flex-col gap-2 border rounded p-5 ml-3"}
// input className={"rounded bg-zinc-600 p-2"}
import './App.css';
import {useEffect, useState} from "react";
function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("http://localhost:5000/users")
.then(response => response.json())
.then(data => {
console.log(data);
setUsers(data);
})
}, []);
return (
<div className="App">
<header className={"bg-zinc-800 min-h-[100vh] flex flex-col items-center justify-center gap-5 text-white"}>
<form className={"flex gap-2"} onSubmit={(event) => {
event.preventDefault();
const data = new FormData(event.target);
fetch("http://localhost:5000/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: data.get('name')
})
}).then(response => response.json())
.then(data => {
console.log("create", users, data);
setUsers([...users, data]);
})
}}>
<input name="name" type={"text"} className={"bg-zinc-600 rounded p-2"}/>
<button type={"submit"} className={"bg-green-700 hover:bg-green-800 rounded p-2"}>Create User</button>
</form>
<ul>
{users.map((user, index) => {
return <li key={index} className={"flex flex-col gap-2 border rounded p-5 ml-3"}>
<div className={"flex items-center gap-2"}>
<p className={"text-2xl"}>{user.name}</p>
<button className={"bg-red-500 hover:bg-red-600 rounded p-2"} onClick={() => {
console.log("delete", user._id);
fetch(`http://localhost:5000/users/${user._id}`, {
method: "DELETE"
}).then(() => {
setUsers(users.filter(u => u._id !== user._id));
})
}}>Delete
</button>
</div>
<form className={"flex gap-2"} onSubmit={(event) => {
event.preventDefault();
const data = new FormData(event.target);
console.log("update", user);
fetch(`http://localhost:5000/users/${user._id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: data.get('name')
})
}).then(response => response.json())
.then(data => {
console.log("update", users, data);
setUsers(users.map(u => {
if (u._id === user._id) {
return data;
}
return u;
}));
})
}}>
<input name="name" type={"text"} className={"rounded bg-zinc-600 p-2"}/>
<button type={"submit"} className={"bg-blue-500 hover:bg-blue-600 rounded p-2"}>Update</button>
</form>
</li>
})}
</ul>
</header>
</div>
);
}
export default App;
Conclusion
You've now built a full-stack web application using React for the frontend, Flask for the backend, MongoDB for the database, and Tailwind CSS for styling. This application allows for basic CRUD operations on user data, demonstrating the integration of frontend and backend technologies.
Repository
Find the complete source code and instructions in the GitHub repository.
Posted on March 13, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.