Learn how to save data to a database in this ⚡️ lightning-fast, lightweight tutorial! Use MongoDB, Node, & Express to persist form data in this tutorial for beginners.

What We Will Build

We will build a simple application that will allow you to save form data into a database! Nothing more, nothing less. But even so, this is a huge accomplishment for anyone that has never actually persisted data to a database. It's not as scary as it may seem!

Requirements

In order to get this up and running there's a couple of basic requirements:

Node.js: I'm currently running Node v10.15.3 on my machine. If you don't already have it, you can install it here: https://nodejs.org/en/

MongoDB Atlas: You could get away with setting up MongoDB via your host machine, but in all honesty, Atlas is so seamless (and free) that it makes the most sense in terms of keeping this tutorial nice and lightweight. Signup for MongoDB Atlas right here: https://www.mongodb.com/cloud

We will also be using the command line/terminal for basic commands, for which I have included screenshots.

You will also need a text editor or IDE of your choice. I will be using WebStorm, but feel free to use whatever floats your boat.

Getting Started

Alright, time to get crackin'.

Let's start by creating a folder on our desktop called simple-data-tutorial.

Next, open up your favorite text editor or IDE and open the empty directory we just created.

The Frontend

index.html

In our simple-data-tutorial project, create a new index.html file. This will serve as the main page for our project and it will contain a simple form in which we will be able to take input from a user and persist it into our database.

Within out index.html file, let's create a simple boilerplate html document like so:

<!doctype html>
<html lang="en">
<head>
    <title>Simple Data | codesnippet.io</title>
</head>
<body>

</body>
</html>

Within the <body> tags, let's create a very simple contact form:

...
<div>
    <form action="/thank-you" method="POST">
        <input type="text" name="name" placeholder="Name">
        <input type="text" name="phone" placeholder="Phone">
        <input type="submit" value="Submit">
    </form>
</div>
...

Note that the action and method attributes here are important. The action is essentially what happens upon a form submission, so in this case, the user will be redirected to the /thank-you page (that we've yet to build), and the method is the HTTP request method, such as GET or POST. We will be using POST in this case.

From the MDN docs:

The POST method is used to submit an entity to the specified resource, often causing a change in state or side effects on the server.

Our index.html file should now look like this:

If you were to preview index.html in your browser, you'd see a rather boring HTML page (I'll leave the styling up to you 😁):

thank-you.html

This page will serve as our 'thank-you' page that the user is redirected to upon completing the form. This will also be a super simple HTML page that you're free to style as you see fit:

With the thank-you.html page created, let's add some simple HTML boilerplate to it like so:

<!doctype html>
<html lang="en">
<head>
    <title>Thank You! | codesnippet.io</title>
</head>
<body>
<div>
    <h1>Thank You!</h1>
    <a href="/">Home</a>
</div>
</body>
</html>

As for the frontend of our lightweight app, that's about it!

The Backend

Next up, let's setup our backend which will handle the processing of our form

First we will need to install our dependency manager.

Within our project, let's initialize NPM. This allows us to quickly import the Node.js modules and packages that we will need for our project. These packages are essentially pieces of code written by others that will save us tons of time and headaches compared to if we were to do it ourselves.

From within the simple-data-tutorial directory, run the command:

npm init

At this point, you will be prompted with a series of questions about your project, feel free to just hit enter all the way through 'til the end:

You should notice a package.json file was generated and added to your project. This is where we can manage all of the dependencies for our project.

Adding project dependencies

Now that we have a way to manage all of our Node dependencies, let's install a few of the packages we will be using:

Express.js: Express is a lightweight web framework that will help us handle HTTP requests in our application. Read more about Express.js here.

Mongoose.js: Mongoose is a super-simple framework that makes working with MongoDB quick and easy. Check out the docs here.

body-parser: Using body-parser makes parsing the data from incoming HTTP requests dead simple. Read up on the docs here.

To install these dependencies within our project, hop back over to your terminal, and within the simple-data-tutorial directory, run the command:

npm install express mongoose body-parser --save

At this point you'll notice that a node_modules directory was added to our project along with a package-lock.json file. Our dependencies that we installed in the step above now live in the node_modules folder, along with any of the dependencies that they require. package-lock.json contains the specific versioning of each and every dependency that's required in your project.

.gitignore

Just as good etiquette, we should create a .gitignore file so that if and when we use version control (i.e. GitHub, Bitbucket, etc.) we are not committing the somewhat large node_modules directory.

From within the .gitignore file, just add this one line:

node_modules/

This will ignore that particular directory when uploading the project to your version control system.

Setting up MongoDB Atlas

Before we're able to actually save data to our database, we need to create an instance first on MongoDB Atlas.

If you haven't already, start by creating an account here: https://www.mongodb.com/cloud

Once you're logged in, create your first cluster. I will be using an 'AWS N. Virginia' instance which qualifies for the 'Free Tier':

For the 'Cluster Tier', select 'M0 Sandbox':

You can leave 'Additional Settings' as is:

For 'Cluster Name' set it to 'simple-data':

Lastly, click that beautiful green 'Create Cluster' button and give it a few minutes to provision your new cluster:

Once the cluster is available, click the 'connect' button:

Next, fill in the information regarding your IP address, click 'Add IP Address', create a database username and password, click 'Create MongoDB user', then click 'Choose a connection method':

Then you will need to select 'Connect Your Application' which will then give us a connection string we can use in our application:

We can now use this connection string to perform database operations between our application and our cloud hosted cluster:

mongodb+srv://simple-data:<password>@simple-data-i4sv5.mongodb.net/test?retryWrites=true&w=majority

Note: Make sure to replace <password> with the password you created for your MongoDB user.

server.js

Now that we have all of our database cluster and dependency management stuff out of the way, it's time for the fun part.

Start by creating a file called server.js. This is where the brunt of our business logic will live.

Within server.js, we will start by importing express which we installed earlier, and instantiating an instance of an express application:

const express = require('express');

const app = express();

At the bottom of server.js, we will configure our application to listen on port 5000 like so:

const PORT = 5000;
app.listen(PORT, () => {
	console.log(`App listening on port ${PORT}`);
});

Awesome! At this point we should be able to run our server. From the command line, run this command:

node server.js

Next, we will setup some routing that will serve our 'homepage' which we created earlier, index.html:

const express = require('express');

const app = express();

app.get('/', (req, res) => {
	res.sendFile(__dirname + '/index.html');
});


const PORT = 5000;
app.listen(PORT, () => {
    console.log(`App listening on port ${PORT}`);
});

Essentially anytime the root ('/') route is visited, our application will serve our index.html file.

Let's try this out to see if it works.

From the terminal, if your application is still running, hit Ctrl + C to stop the server, the run this command again:

node server.js

In your web browser, visit http://localhost:5000, and you should see that beautiful form from earlier:

Express is now serving our index.html file anytime that the root route of our project is requested.

Let's setup the route to our thank-you.html page:

const express = require('express');

const app = express();

app.get('/', (req, res) => {
	res.sendFile(__dirname + '/index.html');
});

app.post('/thank-you', (req, res) => {
	res.sendFile(__dirname + '/thank-you.html');
});

const PORT = 5000;
app.listen(PORT, () => {
    console.log(`App listening on port ${PORT}`);
});

Note: Our /thank-you route is setup as a POST route, which if you remember from earlier when we setup our form in the index.html page, we specified an action of /thank-you and a method of POST.

Hop back over to your terminal, kill the server - Ctrl + C, then restart it by running node server.js.

Visit http://localhost:5000 again and you'll see our favorite form. From there, go ahead and fill out the form and click submit, and boom - you're taken to the thank-you page!

via GIPHY

Form Schema

Now that we have our express routing setup properly, we need to create a schema for our form submissions so that we can maintain some type of structure when we're saving our data to the database.

Start by creating a file named Form.js

Within our newly created Form.js file, we will start by importing mongoose, and utilizing the Schema class to create our form schema like so:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const formSchema = new Schema({
	name: String,
	phone: String
});

mongoose.model('forms', formSchema);

The formSchema instantiates a new Mongoose Schema that we use to define the 'shape' of our data. Essentially we are expecting any form to have a name field and a phone field, both of type String. If we were to try to save our data in some other 'shape', then it would not be persisted to the database. This is a great way to model our data and make sure things are consistent and in the correct format that we want it to be in for our application.

It's worth mentioning that schemas aren't absolutely necessary in MongoDB, but it's very rare that you wouldn't want your data to conform to some sort of consistent data model.

At the bottom of Form.js, you'll notice:

mongoose.model('forms', formSchema);

This will create a new collection named forms that utilizes the formSchema within our MongoDB cluster if a collection named forms does not already exist.

Connecting to MongoDB from our Application

Within server.js, below let's establish our connection to our MongoDB cluster using the connection string from earlier.

Start by requiring the mongoose library into our project.

Then create a variable named db which will hold our connection string, then below that, open up the connection using mongoose, like so:

const express = require('express');
const mongoose = require('mongoose');

const app = express();

const db = 'mongodb+srv://simple-data:SimpleData2019!!@simple-data-i4sv5.mongodb.net/test?retryWrites=true&w=majority';

mongoose.connect(db, { useNewUrlParser: true }, (err, db) => {
    if (db) {
        console.log(`Connected to ${db.host}`);
    } else {
        console.log('Error:', err);
    }
}).catch(err => err);

app.get('/', (req, res) => {
   res.sendFile(__dirname + '/index.html');
});

app.post('/thank-you', (req, res) => {
   res.sendFile(__dirname + '/thank-you.html');
});

const PORT = 5000;
app.listen(PORT, () => {
    console.log(`App listening on port ${PORT}`);
});

Go ahead and restart your server, and at this point we should be connected to our MongoDB cluster:

Processing the Form Data

Next we need to make use of the body-parser library we installed earlier. This will parse the incoming requests we receive from our form via the /thank-you POST route and place the incoming data on the req.body object. Let's also not forget to require the Form.js schema we created earlier, and instantiate a Form object too.

...
const bodyParser = require('body-parser');
require('./Form');

const Form = mongoose.model('forms');
...

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

...

Now that any incoming data that's sent from our form on the index.html page will be placed on the req.body object, we can extract the keys we need (i.e. req.body.name & req.body.phone) and place them into our formSchema

...
app.post('/thank-you', (req, res) => {
	const { name, phone } = req.body;
	const form = new Form({
		name,
		phone
	});
	form.save().catch(err => err);
	console.log(`Name: ${name}\nPhone: ${phone}`);
    res.sendFile(__dirname + '/thank-you.html');
});
...

Here's what our server.js file looks like at this point:

The Moment of Truth

At this point, everything should be good to go! Go ahead and restart your server, and try submitting a form!

You should see the output being logged to your terminal.

Cool....but....what about the database?

Flip back over to MongoDB Atlas.

Click on the name of the database, in our case 'simple-data':

Then click on the 'Collections' tab:

BOOM! If everything went according to plan, you'll see the data you entered into your form, stored in your database!

Congratulations!

via GIPHY

Wrapping up ✅

Being able to save data into a database is such a huge feat. At least it was for me when I first started my journey as a programmer. I hope you feel the same, and if you have any questions at all, please reach out!

Download the Repo 🤖

The repo for this project can be found here: https://github.com/timwheelercom/simple-data


Looking for a Free Contact Form Solution?

If you're a developer that's creating static sites, then setting up a complete form backend for your client or side-project is way more annoying than it has to be.

That's what Sendpoint.io is for. The Simple Form API that's completely FREE! Start receiving form submissions in under 60 seconds.

Use the beautiful Sendpoint.io dashboard to view and analyze all of your form data. All of this in 3 easy steps. 1. Register, 2. Create a form, 3. Add your unique sendpoint to your forms action attribute. That's it!

Don't waste time setting up a form backend. Get started today for free!

Sendpoint.io Logo

Stay Tuned 📺

If you have any questions or improvements, or if you'd like to see additional examples, feel free to reach out to me anytime at tim@timwheeler.com. If you're enjoying my posts, please click here 📬 or subscribe below 👇!