

In this post, I want to show how you can build the front and back end of a website using NodeJS for the back end. Weโll use node to create endpoints, and set up a database in JSON format. Then, weโll create a front end application using React that will post to the database, and also fetch data from it.
For this example, Iโll be making a guestbook, where users can submit their names and leave messages. Because users wonโt need to log in, or retrieve any data, I wonโt need to store anything in a session. Hereโs the way this will likely work:
Basically, we will have this all one one page, with a form for submitting a message, alongside the actual guestbook. To make this work weโโll start by creating the endpoints for our POST and GET requests. Weโll set up our database, deploy it, so that we can create a React app, and pull data from the online API.
Hereโs the order in which I like to do things. You may prefer to work differently. This process makes sense to me, because each step builds on the step before it. During this tutorial, Iโll go through each step in more detail.
To see how the finished project could work, hereโs a link to my project:
http://ethan.jarrell.webdeveloper.surge.sh/GuestBook
Our database collection will contain 2 items:
If you havenโt already done so, go ahead and install MongoDB, and get it running on port 27017. Then, on the command line, weโll create the database.
Weโll call our database signatures. And the collection, guest_signatures.
> Show dbs
> Use signatures
switched to db signatures
> show collections
> db.createCollection(guest_signatures)
Now that we have that set up, we can switch to the text editor, and create the models for the database.
Use the command line to start a new express app. Make the new directory, and then use npm init to create the app. This will automatically create your pkg.JSON file.
Since this will be a very basic app, weโll only need 2 other files in our express app. One for our routes. I like to include all my dependencies in this file as well. Then our second fill will be for our models/schema. Weโll tackle the model file first. It should look something like this:
const mongoose = require('mongoose');
let Schema = mongoose.Schema;
const signatureSchema = new Schema({
guestSignature: {
type: mongoose.Schema.Types.Mixed,
required: true,
},
message: {
type: mongoose.Schema.Types.Mixed,
required: true,
},
})
const Signature = mongoose.model('Signature', signatureSchema);
module.exports = Signature;
Before we create our endpoints here, letโs go ahead an list our dependencies at the top of our file. We donโt need too many.
//====LIST DEPENDENCIES===//
const express = require('express');
const parseurl = require('parseurl');
const bodyParser = require('body-parser');
const path = require('path');
const expressValidator = require('express-validator');
const mongoose = require('mongoose');
const Signature = require('./models/signature.js')
const app = express();
const url = 'mongodb://localhost:27017/signatures';
//=========================//
You donโt necessarily need to connect with mongoose, so feel free to use MongoClient, if you prefer that. Weโre also using the Signature schema that we just created in the previous step.
Now, letโs create our endpoints. We only have one model, and weโre only going to read and write to it for now, so weโre only going to have 2 endpoints.
At our API endpoint, weโll have a GET and a POST. Weโll reference our models, using the find() and create() methods for GET and POST respectively. And our response will need to be in JSON format, so that we can easily access the data there from React later on. Hereโs how those endpoints might look:
//====ROOT DIRECTORY===//
app.get('/', function(req, res) {
res.json('you did it');
});
//==========================//
//====GET ALL SIGNATURES===//
app.get('/api/signatures', function(req, res) {
Signature.find({}).then(eachOne => {
res.json(eachOne);
})
})
//==========================//
//====POST NEW SIGNATURE===//
app.post('/api/signatures', function(req, res) {
Signature.create({
guestSignature: req.body.SignatureOfGuest,
message: req.body.MessageofGuest,
}).then(signature => {
res.json(signature)
});
});
//==========================//
The only thing I didnโt really mention was the req.body.SignatureOfGuest and req.body.MessageofGuest. Everything else in this section refers to something weโve already created, like our database, collections and models. This refers to the name of the field that weโll use in our React App, Our input will have to use the names SignatureOfGuest and MessageofGuest, so weโll need to remember that.
Now, weโll want to connect to our local database from out text editor. If you remember, we had this constant in our list:
const url = 'mongodb://localhost:27017/signatures';
Weโll write a function using this constant to connect to our local database.
//====MONGOOSE CONNECT===//
mongoose.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
}
});
//==========================//
In order to make sure everything is working properly, weโll also need to add an app.listen at the end of our file.
At this point, itโs a good idea to pause, and make sure the endpoints and local connection works. You can do that by using Postman to make GET and POST requests. If the endpoints or connections donโt work, you should be able to diagnose the problem here based on the error messages you receive. If everything is working, it should allow you to appropriately read and write to the database.
Once everything is working, itโs time to set up our account on Heroku and Mlab.
Sign up for a Heroku account here. And create an mLab account here.
Now your database is running on mLab. When you click on the database, you should see some information at the top, telling you how to integrate the connection. It should look something like this:
mongodb://<dbuser>:<dbpassword>@ds79234.mlab.com:9234/signatures
The actual url of the database will just have the username and password replaced with your username and password.
Now letโs head back to our text editor. We currently have the database running locally at this location:
const url = 'mongodb://localhost:27017/signatures';
To change it, so that we are connected to mLab, simply update the url variable with the information from mLab. It should look something like this:
const url = 'mongodb://username:password@ds79234.mlab.com:9234/signatures';
However, youโll likely be putting this on github, or another public place. You donโt want your mlab username and password in a public sphere where anyone can see it. To fix that, weโll set an environment variable on the command line, and then update our url variable one more time in the text editor. On the command line, use this command:
export MONGOLAB_URI="mongodb://username:password@ds79234.mlab.com:9234/signatures';
Of course, replacing it with your own username, password, numbers and database name. Now, back in our text editor, we will change our url variable to the following:
const url = process.env.MONGOLAB_URI;
Weโll also want to change our app.listen to reflect the new port. It could look like this:
app.listen(process.env.PORT || 3000);
console.log('starting applicaiton. Good job!');
This way, it will try to run from mongolab, but if it canโt make the connection, it will still listen on port 3000 by default. This will also allow you to run the app locally or from mlab, in case you want to test changes on the local version.
The final step in making the connection is deploying your code to your Heroku App. to do this, you can use the following code from the command line:
heroku config:set MONGOLAB_URI=mongodb://username:password@ds79234.mlab.com:9234/signatures
Your app should be successfully deployed on heroku, and you can open it from there now. If you are getting errors, double check to make sure itโs running locally. If so, then itโs probably an error along the way in the connection.
In these last two steps, thereโs quite a bit of repetitive code. Iโm going to outline the high level code here.
Use โcreate-react-appโ from the command line to create a new react app.
Now, weโll want to create a form, to allow for user input. Hereโs how we do that.
class GuestBook extends Component
2. Weโll use a constructor and super method to pass props down.
constructor(props) {
super(props);
3. Use the this keyword to handle the name and message of guest, and bind it to (this).
this.handleSignatureOfGuest = this.handleSignatureOfGuest.bind(this);
this.handleMessageofGuest = this.handleMessageofGuest.bind(this);
4. Set the state of the name and message of guest to an empty string.
this.state = {
SignatureOfGuest: "",
MessageofGuest: "",
};
5. Listen for an event on the state of both the name and message input.
handleSignatureOfGuest(event) {
this.setState({ SignatureOfGuest: event.target.value });
}
handleMessageofGuest(event) {
this.setState({ MessageofGuest: event.target.value });
}
6. Create a function that changes the name and message to the value of the target input.
addToGuestBook = event => {
event.preventDefault();
this.setState({
SignatureOfGuest: event.target.value,
MessageofGuest: event.target.value,
});
7. Iโm now using axios to post the input data to our database, which is on heroku.
axios.post('<your-heroku-url here>', {
SignatureOfGuest: this.state.SignatureOfGuest,
MessageofGuest: this.state.MessageofGuest,
})
.then(response => {
console.log(response, 'Signature added!');
})
.catch(err => {
console.log(err, 'Signature not added, try again');
});
8. Then Iโm resetting the state of the input to an empty string.
this.setState({
SignatureOfGuest: "",
MessageofGuest: "",
});
};
9. Finally, weโll make a render method, and return our page with the input fields. Inside the input of each field, weโll give it an onChange, name, and value. the onChange will be set to the.handlemessage or this.handlename, for each field. The name of each field will be set to what we called it in our node app. The value will use state, and weโll set that to this.state.message, and this.state.name.
<input
onChange={this.handleSignatureOfGuest}
name="SignatureOfGuest"
className="NameinputForm"
value={this.state.SignatureOfGuest}
placeholder="Enter your name"
/>
<textarea
onChange={this.handleMessageofGuest}
name="MessageofGuest"
className="MessageinputForm"
value={this.state.MessageofGuest}
placeholder="Type a message"
/>
10. Then weโll add a submit button, where we call the function from earlier.
<button
className="submitbuttonguestbook"
type="submit"
onClick={this.addToGuestBook}
>
Submit to Guestbook<i className="GuestBookButton2" aria-hidden="true" />
</button>
Now weโll make another component where weโll render the data thatโs being stored in our database. Then we can export that component, and put it on our guestbook page.
Inside this component weโll do the following:
class GuestNames extends Component {
2. Weโll use a constructor and super method to pass props down.
constructor(props) {
super(props);
3. Use this.state to set the state of our guestbook messages to an empty string.
this.state = {
messages: "",
};
4. Use a componentDidMount lifecycle method
componentDidMount() {
5. Inside that method weโll use fetch and the url of our heroku api to fetch the information from the database.
fetch('<your-heroku-url-goes-here>')
.then(results => {
return results.json();
6. Weโll map over the data, and return the data we want.
data.map((msg) => {
return(
<div key={msg.results}>
<h3 className="h3msg">{msg.message}</h3>
<h2 className="h2sig">-{msg.guestSignature}</h2>
</div>
7. Now weโll use this.setState to set the state of the messages to the new state using the data we just fetched.
this.setState({messages: messages});
8. Now weโll create render mehod.
render() {
9. Inside the render method, weโll create JSX elements to render our data inside the component. Iโm using this.state.messages inside an <h6> tag.
return (
<div className="guestdataContainer">
<h6>Guestbook Messages</h6>
{this.state.messages}
</div>
10. Finally, weโll export the component, so we can use it on other pages.
export default GuestNames;
Again, if you have any questions feel free to reach out. Thanks!
Create your free account to unlock your custom reading experience.