React.js + Python + MongoDB CRUD application example

In this section, we will learn how to develop a  web application that is a basic User Management Application using MongoDB, React.js, Python, and Flask. GitHub repository link is provided at the end of this tutorial. You can download the source code.

We’re gonna build the application with the following components:

After completing this tutorial what we will build?

We will build a full-stack web application that is a basic User Management Application with CRUD features:

    • Create User
    • List User
    • Update User
    • Delete User
    • View User

Following is the screenshot of our application -

-View all Users:


-Add a User:


-Update User:


-View User

We divided this tutorial into two parts. 

PART 1 - Rest APIs Development using Python and Flask

PART 2 - UI development using React.js   


PART 1 - Rest APIs Development using Python and Flask

These are APIs that Python Flask App will export: 

  1. GET all User's        :     /api/v1/users
  2. GET User by ID     :     /api/v1/users/{_id}
  3. POST User             :     /api/v1/users 
  4. PUT User               :     /api/v1/users/{_id} 
  5. DELETE User       :     /api/v1/users/{_id}

Back end project structure:


In this project, I'm using flask, flask_cors & pymongo dependencies, use the following command to install the same.
pip install flask flask_cors pymongo

database.yaml
uri: 'mongodb://localhost:27017/knf-dev'


app.py
from flask import Flask, render_template, request, jsonify
from pymongo import MongoClient
from bson.objectid import ObjectId
from flask_cors import CORS
import yaml

app = Flask(__name__)
config = yaml.load(open('database.yaml'))
client = MongoClient(config['uri'])
# db = client.lin_flask
db = client['knf-dev']
CORS(app)

@app.route('/')
def index():
return render_template('home.html')

@app.route('/users', methods=['POST', 'GET'])
def data():
# POST a data to database
if request.method == 'POST':
body = request.json
firstName = body['firstName']
lastName = body['lastName']
emailId = body['emailId']
# db.users.insert_one({
db['users'].insert_one({
"firstName": firstName,
"lastName": lastName,
"emailId":emailId
})
return jsonify({
'status': 'Data is posted to MongoDB!',
'firstName': firstName,
'lastName': lastName,
'emailId':emailId
})
# GET all data from database
if request.method == 'GET':
allData = db['users'].find()
dataJson = []
for data in allData:
id = data['_id']
firstName = data['firstName']
lastName = data['lastName']
emailId = data['emailId']
dataDict = {
'id': str(id),
'firstName': firstName,
'lastName': lastName,
'emailId': emailId
}
dataJson.append(dataDict)
print(dataJson)
return jsonify(dataJson)

@app.route('/users/<string:id>', methods=['GET', 'DELETE', 'PUT'])
def onedata(id):

# GET a specific data by id
if request.method == 'GET':
data = db['users'].find_one({'_id': ObjectId(id)})
id = data['_id']
firstName = data['firstName']
lastName = data['lastName']
emailId = data['emailId']
dataDict = {
'id': str(id),
'firstName': firstName,
'lastName': lastName,
'emailId':emailId
}
print(dataDict)
return jsonify(dataDict)
# DELETE a data
if request.method == 'DELETE':
db['users'].delete_many({'_id': ObjectId(id)})
print('\n # Deletion successful # \n')
return jsonify({'status': 'Data id: ' + id + ' is deleted!'})

# UPDATE a data by id
if request.method == 'PUT':
body = request.json
firstName = body['firstName']
lastName = body['lastName']
emailId = body['emailId']

db['users'].update_one(
{'_id': ObjectId(id)},
{
"$set": {
"firstName":firstName,
"lastName":lastName,
"emailId": emailId
}
}
)

print('\n # Update successful # \n')
return jsonify({'status': 'Data id: ' + id + ' is updated!'})

if __name__ == '__main__':
app.debug = True
app.run()

Run the server file using the following command. Make sure your MongoDB server is still running : 
$ python3 app.py
Your application server will run locally at http://localhost:5000




PART 2 - UI development using React.js

Now we are going to develop a React.js web application.

Package structure - Front end:




package.json

A package.json is a JSON file that subsists at the root of a Javascript/Node project. It holds metadata pertinent to the project and is utilized for managing the project's dependencies, scripts, version, and a whole lot more.
{
"name": "react-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-
event": "^7.2.1",
"axios": "^0.19.2",
"bootstrap": "^4.5.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}



CreateUserComponent.json

import React, { Component } from 'react'

import UserService from '../services/UserService';
class CreateUserComponent extends Component {
constructor(props) {
super(props)
this.state = {
// step 2
id: this.props.match.params.id,
firstName: '',
lastName: '',
emailId: ''
}
this.changeFirstNameHandler = this.changeFirstNameHandler.bind(this);
this.changeLastNameHandler = this.changeLastNameHandler.bind(this);
this.saveOrUpdateUser = this.saveOrUpdateUser.bind(this);
}
// step 3
componentDidMount() {
// step 4
if (this.state.id === '_add') {
return
} else {
UserService.getUserById(this.state.id).then((res) => {
let user = res.data;
this.setState({
firstName: user.firstName,
lastName: user.lastName,
emailId: user.emailId
});
});
}
}
saveOrUpdateUser = (e) => {
e.preventDefault();
let user = { firstName: this.state.firstName,
lastName: this.state.lastName, emailId: this.state.emailId };
console.log('user => ' + JSON.stringify(user));
// step 5
if (this.state.id === '_add') {
UserService.createUser(user).then(res => {
this.props.history.push('/users');
});
} else {
UserService.updateUser(user, this.state.id).then(res => {
this.props.history.push('/users');
});
}
}
changeFirstNameHandler = (event) => {
this.setState({ firstName: event.target.value });
}
changeLastNameHandler = (event) => {
this.setState({ lastName: event.target.value });
}
changeEmailHandler = (event) => {
this.setState({ emailId: event.target.value });
}
cancel() {
this.props.history.push('/users');
}
getTitle() {
if (this.state.id === '_add') {
return <h3 className="text-center">Add User</h3>
} else {
return <h3 className="text-center">Update User</h3>
}
}
render() {
return (
<div>
<br></br>
<div className="container">
<div className="row">
<div className="card col-md-6 offset-md-3 offset-md-3">
{
this.getTitle()
}
<div className="card-body">
<form>
<div className="form-group">
<label> First Name: </label>
<input placeholder="First Name" name="firstName" className="form-control"
value={this.state.firstName} onChange={this.changeFirstNameHandler} />
</div>
<div className="form-group">
<label> Last Name: </label>
<input placeholder="Last Name" name="lastName" className="form-control"
value={this.state.lastName} onChange={this.changeLastNameHandler} />
</div>
<div className="form-group">
<label> Email Id: </label>
<input placeholder="Email Address" name="emailId" className="form-control"
value={this.state.emailId} onChange={this.changeEmailHandler} />
</div>
<button className="btn btn-success" onClick={this.saveOrUpdateUser}>
Save</button>
<button className="btn btn-danger" onClick={this.cancel.bind(this)}
style={{ marginLeft: "10px" }}>Cancel</button>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default CreateUserComponent




ListUserComponent.jsx

import React, { Component } from 'react'

import UserService from '../services/UserService'
class ListUserComponent extends Component {
constructor(props) {
super(props)
this.state = {
users: []
}
this.addUser = this.addUser.bind(this);
this.editUser = this.editUser.bind(this);
this.deleteUser = this.deleteUser.bind(this);
}
deleteUser(id) {
UserService.deleteUser(id).then(res => {
this.setState({ users: this.state.users.
filter(user => user.id !== id) });
});
}
viewUser(id) {
this.props.history.push(`/view-user/${id}`);
}
editUser(id) {
this.props.history.push(`/add-user/${id}`);
}
componentDidMount() {
UserService.getUsers().then((res) => {
this.setState({ users: res.data });
});
}
addUser() {
this.props.history.push('/add-user/_add');
}
render() {
return (
<div>
<h2 className="text-center">Users List</h2>
<div className="row">
<button className="btn btn-primary" onClick={this.addUser}>
Add User</button>
</div>
<br></br>
<div className="row">
<table className="table table-striped table-bordered">
<thead>
<tr>
<th> User First Name</th>
<th> User Last Name</th>
<th> User Email Id</th>
<th> Actions</th>
</tr>
</thead>
<tbody>
{
this.state.users.map(
user =>
<tr key={user.id}>
<td> {user.firstName} </td>
<td> {user.lastName}</td>
<td> {user.emailId}</td>
<td>
<button onClick={() => this.editUser(user.id)} className="btn btn-info">
Update </button>
<button style={{ marginLeft: "10px" }} onClick={() => this.
deleteUser(user.id)} className="btn btn-danger">Delete </button>
<button style={{ marginLeft: "10px" }} onClick={() => this.
viewUser(user.id)} className="btn btn-info">View </button>
</td>
</tr>
)
}
</tbody>
</table>
</div>
</div>
)
}
}
export default ListUserComponent




UpdateUserComponent.jsx

import React, { Component } from 'react'

import UserService from '../services/UserService';
class UpdateUserComponent extends Component {
constructor(props) {
super(props)
this.state = {
id: this.props.match.params.id,
firstName: '',
lastName: '',
emailId: ''
}
this.changeFirstNameHandler = this.changeFirstNameHandler.bind(this);
this.changeLastNameHandler = this.changeLastNameHandler.bind(this);
this.updateUser = this.updateUser.bind(this);
}
componentDidMount() {
UserService.getUserById(this.state.id).then((res) => {
let user = res.data;
this.setState({
firstName: user.firstName,
lastName: user.lastName,
emailId: user.emailId
});
});
}
updateUser = (e) => {
e.preventDefault();
let user = { firstName: this.state.firstName,
lastName: this.state.lastName, emailId: this.state.emailId };
console.log('user => ' + JSON.stringify(user));
console.log('id => ' + JSON.stringify(this.state.id));
UserService.updateUser(user, this.state.id).then(res => {
this.props.history.push('/users');
});
}
changeFirstNameHandler = (event) => {
this.setState({ firstName: event.target.value });
}
changeLastNameHandler = (event) => {
this.setState({ lastName: event.target.value });
}
changeEmailHandler = (event) => {
this.setState({ emailId: event.target.value });
}
cancel() {
this.props.history.push('/users');
}
render() {
return (
<div>
<br></br>
<div className="container">
<div className="row">
<div className="card col-md-6 offset-md-3 offset-md-3">
<h3 className="text-center">Update User</h3>
<div className="card-body">
<form>
<div className="form-group">
<label> First Name: </label>
<input placeholder="First Name" name="firstName" className="form-control"
value={this.state.firstName} onChange={this.changeFirstNameHandler} />
</div>
<div className="form-group">
<label> Last Name: </label>
<input placeholder="Last Name" name="lastName" className="form-control"
value={this.state.lastName} onChange={this.changeLastNameHandler} />
</div>
<div className="form-group">
<label> Email Id: </label>
<input placeholder="Email Address" name="emailId" className="form-control"
value={this.state.emailId} onChange={this.changeEmailHandler} />
</div>
<button className="btn btn-success" onClick={this.updateUser}>Save</button>
<button className="btn btn-danger" onClick={this.cancel.bind(this)}
style={{ marginLeft: "10px" }}>Cancel</button>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default UpdateUserComponent




ViewUserComponent.jsx
import React, { Component } from 'react'
import UserService from '../services/UserService'
class ViewUserComponent extends Component {
constructor(props) {
super(props)
this.state = {
id: this.props.match.params.id,
user: {}
}
}
componentDidMount() {
UserService.getUserById(this.state.id).then(res => {
this.setState({ user: res.data });
})
}
render() {
return (
<div>
<br></br>
<div className="card col-md-6 offset-md-3">
<h3 className="text-center"> View User Details</h3>
<div className="card-body">
<div className="row">
<label> User First Name: </label>
<div> {this.state.user.firstName}</div>
</div>
<div className="row">
<label> User Last Name: </label>
<div> {this.state.user.lastName}</div>
</div>
<div className="row">
<label> User Email ID: </label>
<div> {this.state.user.emailId}</div>
</div>
</div>
</div>
</div>
)
}
}
export default ViewUserComponent



UserService.js
import axios from 'axios';

const USER_API_BASE_URL = "http://localhost:5000/users";

class UserService {

getUsers(){
return axios.get(USER_API_BASE_URL);
}

createUser(user){
return axios.post(USER_API_BASE_URL, user);
}

getUserById(userId){
return axios.get(USER_API_BASE_URL + '/' + userId);
}

updateUser(user, userId){
return axios.put(USER_API_BASE_URL + '/' + userId, user);
}

deleteUser(userId){
return axios.delete(USER_API_BASE_URL + '/' + userId);
}
}

export default new UserService()



App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'
import ListUserComponent from './components/ListUserComponent';
import HeaderComponent from './components/HeaderComponent';
import FooterComponent from './components/FooterComponent';
import CreateUserComponent from './components/CreateUserComponent';
import UpdateUserComponent from './components/UpdateUserComponent';
import ViewUserComponent from './components/ViewUserComponent';

function App() {
return (
<div>
<Router>
<HeaderComponent />
<div className="container">
<Switch>
<Route path = "/" exact component = {ListUserComponent}></Route>
<Route path = "/users" component = {ListUserComponent}></Route>
<Route path = "/add-user/:id" component = {CreateUserComponent}></Route>
<Route path = "/view-user/:id" component = {ViewUserComponent}></Route>
</Switch>
</div>
<FooterComponent />
</Router>
</div>
);
}
export default App;



Run


npm install & npm start


Your application will run locally at http://localhost:3000



Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Spring Boot + Mockito simple application with 100% code coverage

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete