Web applications in React, Bootstrap, MongoDB, Express/Printable version
This is the print version of Web applications in React, Bootstrap, MongoDB, Express You won't see this message or any elements not part of the book's content when you print or preview this page. |
The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/Web_applications_in_React,_Bootstrap,_MongoDB,_Express
Create a MongoDB database locally
- 1) Install MongoDB Community Edition on your PC
from here: https://docs.mongodb.com/manual/administration/install-community/
- 2) Create a folder named mongo_database on proprio pc and a subfolder under it named data_items
- 3) Open a terminal in the mongo_database folder and type:
mongod --dbpath = data_items --bind_ip 127.0.0.1
in this way the MongoDB server is started in the url 127.0.0.1 at port 27017
- 4) Open another terminal in the mongo_database folder and type in sequence:
mongo
db
use db_items
db
exit
In this way the database we will use will be called: db_items
- 5)Before starting the web server that we will create, the MongoDB server must be started with instruction 3)
Create a Node Express web server locally that connects to a MongoDB database
Installing Node.Js and Express Generator
edit- 1) Node.Js is a Javascript framework that also allows you to write server-side code and therefore, in particular, allows you to create an Express web server. npm (short for Node Package Manager [2]) is the default package manager for the Node.js JavaScript runtime environment. It consists of a command line client, also called npm, and an online database of public and private packages, called the npm registry.
- 2) Install Node.js on your PC from here: https://nodejs.org/
- 3) In the terminal type:
node -v
npm -v
to verify that both node and npm have been installed correctly on your system.
- 4) Install the express-generator package via npm by typing in the terminal:
npm install express-generator -g
- 5) Open the terminal in Documents and type:
express ItemsServer
- 6) In the ItemsServer folder, type in the terminal:
npm install
- 7) In the ItemsServer folder type in the terminal to start the server:
npm start
- 8) In the browser at the link http://localhost:3000/ the message "Welcome to Express" will appear.A Node Express web server is done !
API REST and MONGOOSE
editThe requests that the client makes to the server are made through the REST API. For example, if you are making a GET request, you are asking the server to return a resource. If you make a POST request, the server is being asked to create a new resource. If you are making a PUT request, you are asking the server to update an existing resource. And if you issue a DELETE request, the server is being asked to delete the resource identified by the particular URI. The exchange of data between client and server takes place in JSON format, which represents the standard with which Javascript objects are built. For example, the URL http://localhost:3000/items/234 means that the client asks the server to act on item 234, on which it is possible to perform GET, PUT or DELETE operations. To implement REST API calls on the MongoDB database you need to install mongoose:
- 1) In the ItemsServer folder open a terminal and type:
npm install mongoose@5.7.0 –save
- 2) Create a mongoose schema for the document items of the MongoDB database and insert it in the items.js file inside the models sub folder of the ItemServer folder
// items.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var itemSchema = new Schema({
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
measure: {
type: String,
required: true
}
}, {
timestamps: true
});
var Items = mongoose.model('Item', itemSchema);
module.exports = Items;
- 3) In the subFolder routes of ItemServer, create the file itemRouter.js :
// itemRouter.js
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const Items = require('../models/items');
const itemRouter = express.Router();
itemRouter.use(bodyParser.json());
itemRouter.route('/')
.get((req,res,next) => {
Items.find({})
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
})
.post((req, res, next) => {
Items.create(req.body)
.then((resp) => {
console.log('Item Created ', resp);
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
})
.put((req, res, next) => {
res.statusCode = 403;
res.end('PUT operation not supported on /items');
})
.delete((req, res, next) => {
Items.remove({})
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
});
itemRouter.route('/:itemId')
.get((req,res,next) => {
Items.findById(req.params.itemId)
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
})
.post((req, res, next) => {
res.statusCode = 403;
res.end('POST operation not supported on /items/'+ req.params.itemId);
})
.put((req, res, next) => {
Items.findByIdAndUpdate(req.params.itemId, {
$set: req.body
}, { new: true })
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
})
.delete((req, res, next) => {
Items.findByIdAndRemove(req.params.itemId)
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
});
module.exports = itemRouter;
- 4) Edit the app.js file in the ItemsServer folder :
// app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var itemsRouter = require('./routes/itemRouter');
var app = express();
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
const url = 'mongodb://localhost:27017/db_items';
const options = {
useMongoClient: true,
autoIndex: false, // Don't build indexes
reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
reconnectInterval: 500, // Reconnect every 500ms
poolSize: 10, // Maintain up to 10 socket connections
// If not connected, return errors immediately rather than waiting for reconnect
bufferMaxEntries: 0
};
mongoose.connect(url, options);
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
next();
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/items', itemsRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
- 5) We created a Node Express web server that connects locally to a MongoDB database.
Use the Postman program to perform read, create, update, delete operations on a MongoDB database through a Node Express web server
- 1) Download and install the Postman program from here: https://www.postman.com/downloads/
- 2) Start the MongoDB server, opening a terminal in the mongo_database folder and typing:
mongod --dbpath = data_items --bind_ip 127.0.0.1
- 3) Start the Node Express web server, opening a terminal in the ItemsServer folder and typing:
npm start
- 4) Open the Postman program and create a new item in the database via the POST method:
- 5) Change the item via the PUT method and the item ID:
- 6) View the data in the database via the GET method:
- 7) Delete the item by the DELETE method and the item ID
Create a React app with Bootstrap that performs read, create, update, delete operations on a MongoDB database via a Node Express web server
Now we will create the Front end in React-Bootstrap that connects to the Node Express web server and through Rest API acts on the MongoDB database with GET, POST, PUT, DELETE operations on the items in a warehouse:
- 1) In the Documents folder open a terminal and type:
npx create-react-app items-app
- 2) In the items-app folder open a terminal and type to install the Bootstrap css framework:
npm install react-bootstrap bootstrap@5.1.3
- 3) Replace the App.js file with the following:
//App.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Items from './Componenti/Items';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
baseUrl : 'http://localhost:3000/',
};
}
render() {
return (
<div className="container-fluid">
<title>Manage Items</title>
<h1 className="text-center text-primary">Manage Items</h1>
<h2 className="text-center text-secondary">with React, Bootstrap, MongoDB, Express</h2>
<Items baseUrl={this.state.baseUrl} />
</div>
);
}
}
export default App;
- 4) Create a Components sub folder in which to insert the following files:
//items.js
import 'bootstrap/dist/css/bootstrap.min.css';
import Tabella from './Tabella';
import React from 'react';
import ModalView from './ModalView';
class Items extends React.Component
{
constructor(props)
{
super(props);
this.state = {
inputID: "",
inputName: "",
inputQuantity: "",
inputMeasure: "",
show: false,
message: ''
};
this.handleClickNuovo = this.handleClickNuovo.bind(this);
this.handleClickSalva = this.handleClickSalva.bind(this);
this.handleChangeName = this.handleChangeName.bind(this);
this.handleChangeQuantity = this.handleChangeQuantity.bind(this);
this.handleChangeMeasure = this.handleChangeMeasure.bind(this);
this.handleClose = this.handleClose.bind(this);
}
handleChangeName(event)
{
this.setState({
inputName: event.target.value,
});
}
handleChangeQuantity(event)
{
this.setState({
inputQuantity: event.target.value,
});
}
handleChangeMeasure(event)
{
this.setState({
inputMeasure: event.target.value,
});
}
handleClickNuovo(event)
{
this.setState({
inputID: "",
inputName: "",
inputQuantity: "",
inputMeasure: "",
show: false,
});
}
handleClickSalva(event)
{
if (this.state.inputName === "" ||
this.state.inputQuantity === "" ||
this.state.inputMeasure === "" )
{
this.setState({
show: true,
message: 'Tutti i campi devono essere compilati! '
})
}
else if (isNaN(parseFloat(this.state.inputQuantity)))
{
this.setState({
show: true,
message: 'Quantity is a number!'
})
} else
{
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: this.state.inputName,
quantity: this.state.inputQuantity,
measure: this.state.inputMeasure
})
};
fetch(this.props.baseUrl + 'items', requestOptions)
.then(() => console.log('Item created'))
.catch(err => {
console.error(err);
});
this.setState({
show: true,
message: 'Item created!'
})
}
}
handleClose(event)
{
this.setState({
show: false,
});
}
render()
{
return (
<div class="row">
<div className="col-md-12">
<div className="card" >
<div className="card-body">
<h5 className="card-title">Item:</h5>
<div className="input-group mb-3">
<span className="input-group-text">Item name:</span>
<input
type="text"
className="form-control"
value={this.state.inputName}
onChange={this.handleChangeName}
/>
<span className="input-group-text">Quantity:</span>
<input
type="text"
className="form-control"
value={this.state.inputQuantity}
onChange={this.handleChangeQuantity}
/>
<span className="input-group-text">Measure:</span>
<input
type="text"
className="form-control"
value={this.state.inputMeasure}
onChange={this.handleChangeMeasure}
/>
</div>
<button onClick={this.handleClickNuovo} className="btn btn-primary">
New
</button>
<button onClick={this.handleClickSalva} className="btn btn-secondary">
Save
</button>
<button className="btn btn-success">
Update
</button>
<ModalView
message={this.state.message} show={this.state.show} handleClose={this.handleClose}
/>
</div>
</div>
<Tabella baseUrl={this.props.baseUrl} />
</div>
</div>
);
}
}
export default Items;
//Tabella.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import ModalViewEdit from './ModalViewEdit';
class Tabella extends React.Component
{
constructor(props)
{
super(props);
this.state = {
rows: [],
show: false,
editRow:{}
}
this.handleDelete = this.handleDelete.bind(this);
this.handleEdit = this.handleEdit.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleClickEvent = this.handleClickEvent.bind(this);
this.handleClick = this.handleClick.bind(this);
}
componentDidMount()
{
this.handleClick();
document.addEventListener('click', this.handleClickEvent)
}
componentWillUnmount()
{
document.removeEventListener('click', this.handleClickEvent)
}
handleClickEvent(event)
{
this.handleClick();
}
handleClick()
{
fetch(this.props.baseUrl + 'items').then(function (data)
{
return data.json();
}).then(json =>
{
this.setState({
rows: json.map((row) =>
<tr >
<th scope="row" >{row._id}</th>
<td>{row.name}</td>
<td>{row.quantity}</td>
<td>{row.measure}</td>
<td ><button id={row._id} onClick={this.handleEdit} className="btn btn-info">
Edit
</button></td>
<td ><button id={row._id} onClick={this.handleDelete} className="btn btn-danger">
Delete
</button></td>
</tr>),
});
});
}
handleDelete = (e) =>
{
const key = e.currentTarget.getAttribute("id");
fetch(this.props.baseUrl + 'items/' + key,
{
method: 'DELETE',
})
.then(() => console.log('Item deleted: ' + key))
.catch(err =>
{
console.error(err);
});
this.handleClick();
}
handleEdit = (e) =>
{
const key = e.currentTarget.getAttribute("id");
fetch(this.props.baseUrl + 'items/' +key).then(function (data)
{
return data.json();
}).then(json =>
{
this.setState({
editRow: json,
show:true,
});
});
}
handleClose(event)
{
this.setState({
show: false,
editRow:{}
});
}
render()
{
return (
<>
<table className="table table-striped" >
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Quantity</th>
<th scope="col">Measure</th>
</tr>
</thead>
<tbody>
{this.state.rows}
</tbody>
</table>
{this.state.show && <ModalViewEdit
baseUrl={this.props.baseUrl} editRow={this.state.editRow} show={this.state.show} handleClose={this.handleClose}
/>}
</>
);
}
}
export default Tabella;
- 5) In the terminal type:
npm start
and use the program.