DEV Community

EidorianAvi
EidorianAvi

Posted on

 

Node.js, MongoDB, and Express Rest API (Part 1)

I've decided in my coding journey it's time to build a MERN application. What is a MERN App you ask? Let's break it down:

  • MongoDB: A NoSQL style of database. This is where the data for the back-end is stored and is done so in the style of documents and collections.

  • Express: A back-end framework built for node. It's the de facto method of creating an API using node.

  • React: A front-end JavaScript library sometimes called a framework developed by Facebook. Generally used to build single page applications and the UI.

  • Node: A back-end JavaScript runtime environment that allows for the use of JavaScript outside of a web browser where it was originally designed for.

That makes MERN. Now I've done some React tutorials but that's the front-end portion of the stack. Today I wanna go over how to setup a back-end using the rest. That leaves us with Node.js to develop using JavaScript, Express as a framework for node to set up the API, and MongoDB as the database for storage. Let's go.

The Setup

I'm going to continue under the assumption that you already have node and npm installed as well as an account created with MongoDB and Postman installed for testing your requests. If you haven't done so at this point, what's stopping you.

Initialize the Project

First things first in the projects root lets initialize our app and create a package.json for package management.

npm init -y
Enter fullscreen mode Exit fullscreen mode

The -y flag is to confirm yes to all default options. You can also do this manually and leave the flag off.

Install Some Packages

Now in the projects root lets install some packages that we will be using to build this out.

npm install express mongoose dotenv
Enter fullscreen mode Exit fullscreen mode

To elaborate on what these are:

  • express: The node framework mentioned multiple times up to this point.
  • mongoose: An Object Data Modeling (ODM) library used for MongoDB and Node to manage relationships between data and create the schema.
  • dotenv: This package allows for the use of .env file for storing data you wouldn't want accessible such as credentials and keys.

Create a Database

1.On MongoDB go ahead and create a new project and call it what you want.

2.Once the project is created, create a cluster in the project. I personally went with all the defaults and free options.

3.Now go to the Database Access which should be under Security and select +ADD NEW DATABASE USER and create a username and password.

4.Go back to Clusters under Storage and on the free cluster you created click on Connect. Go through the prompts of whitelisting your IP address then select Connect Your Application. It should give you a string you are able to copy that looks like this:

mongodb+srv://EidorianAvi:<password>@cluster0.i3fzx.mongodb.net/<dbname>?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

Go ahead and put in your password and name the db what you want at this point.

5.Back in your root directory of your express project go ahead and create a .env file. In this file assign this string you just copied with the password and dbname filled out to a variable like so:

DB_CONNECTION="mongodb+srv://EidorianAvi:<password>@cluster0.i3fzx.mongodb.net/<dbname>?retryWrites=true&w=majority"
Enter fullscreen mode Exit fullscreen mode

6.Celebrate. You've created your MongoDB database and brought the connection string into your project in the .env file so you can use it but it's not available to the public.

Start Building the App

Okay so at this point of the project we've initialized our packages.json file, installed the appropriate packages, created a database for storage and brought the connection string into our .env file. Now we can start building up the API. Let's create our app.js.

touch app.js
Enter fullscreen mode Exit fullscreen mode

Now inside of our app.js lets bring express into the file and initialize it like so:

const express = require('express');
const app = express();
Enter fullscreen mode Exit fullscreen mode

Let's also bring mongoose into the file and require our .env file like so:

const mongoose = require('mongoose');
require('dotenv/config');
Enter fullscreen mode Exit fullscreen mode

Awesome. Now that that's done right below all of that we're going to use some built in express middleware to turn any requests into JSON format.

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
Enter fullscreen mode Exit fullscreen mode

Now we can set up the port we want our app to listen to for requests as well as set up our route for a request to the root and connect to the database using that mongoose package we installed earlier.

// Root Route
app.get('/', (req, res) => {
    res.send('This is the root URL');
});

//Connect to DB
mongoose.connect( process.env.DB_CONNECTION, { useNewUrlParser: true,useUnifiedTopology: true }, () => {
    console.log("Connected to database");
});

// Listen on port 4000 for requests
app.listen(4000);
Enter fullscreen mode Exit fullscreen mode
  • First I set up the root route for a get request that takes in the name of the route, and a function that takes in the response and request and decides what to do with them.

  • I then set up the database connection using mongoose.connect. That took in three things, first the DB_CONNECTION that we stored in our .env file, we are able to access that as process.env.DB_CONNECTION. Second a couple options don't worry too much about those for now. Lastly a callback function once the connection is complete. I set it log to the console that you have connected to the database.

  • Lastly I made the app listen to port 4000 on our localhost.

Test it out. Run node app.js and on port 4000 of your localhost you should see the response we sent back at the root as well as see in your console that it has connected to the database.

Setting Up a Model

Okay so now that we are able to make a request to our application as well as connect to the database let's go ahead and set up a model. I created a models folder and made one model file inside of it for dogs:

mkdir models
touch models/Dog.js
Enter fullscreen mode Exit fullscreen mode

Now we can use mongoose to create the schema for the model as well as to export it as model like so:

const mongoose = require('mongoose');

const DogSchema = mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    breed: String
});

module.exports = mongoose.model('Dogs', DogSchema);
Enter fullscreen mode Exit fullscreen mode
  • I brought in mongoose.
  • I created a DogSchema using mongoose.Schema and passed in an object with the desired schema.
  • I put validation on the name to show that it is required.
  • I exported it as the Dogs model using mongoose.model

Setting up Routes

Now that we have a model to work with lets also build some routes for the Dogs model. At the root of the app:

mkdir routes
touch routes/dogs.js
Enter fullscreen mode Exit fullscreen mode

Inside our dogs routes lets bring in the express router, initialize it and export it as well as the Dog model we just created:

const express = require('express');
const router = express.Router();
const Dog = require('../models/Dog');

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Now back in our app.js lets use some middleware to redirect all requests going to '/dogs' to hit the routes we are about to create:

const dogsRoute = require('./routes/dogs');

app.use('/dogs', dogsRoute);
Enter fullscreen mode Exit fullscreen mode

Nice.

The GET and POST Requests

Okay so this will be the last part for today.

Let's set up a response to our root /dogs route to make sure it's working right.

router.get('/', (req, res) => {
    res.send('Dogs page');
});
Enter fullscreen mode Exit fullscreen mode

If you went to localhost:4000/dogs our app will send back plain text "Dogs page". If that's working out for you congrats you successfully set up the path to your /dogs route.

So let's now see if we can successfully post something to the MongoDB database we set up earlier.

router.post('/add-dog', (req, res) => {
    const dog = new Dog({
        name: req.body.name,
        breed: req.body.breed,
    });

    dog.save()
        .then(result => {
            res.json(result);
        })
        .catch(e => {
            res.json(e);
        });
});
Enter fullscreen mode Exit fullscreen mode
  • I made a post request to our router at the /dogs/add-dog path.
  • I created a new instance of the Dog model that will take in the request and assigned it a constant.
  • I saved it to the database and if successful sent back the entry of the database in JSON format.
  • If it failed there is a catch that will respond with the error in JSON format.

At this point open Postman. If you can make a GET request to localhost:4000/dogs and it returns "Dogs page" that's a good sign.
If you can make a POST request to localhost:4000/dogs/add-dog and the server responds with the newly created entry you're in good shape. Go check out your collections on MongoDB and you should see a newly posted dogs collection with a new dog document.

Wrap Up

You now have a back-end application built using MongoDB, Express, and Node. You can successfully make a request to a specific route you created and you can also successfully make a POST request that stores data in an actual database. Good stuff right? I know there's a bit more to cover on building a more fleshed out API but that'll be for next week. We will cover how to GET actual data from the database, PUT or update data, and how to DELETE from the database.

If you have any questions feel free to reach out to me but otherwise I hope you feel more confident setting up a basic node API. Thanks for checking this out and as always happy coding!

Top comments (7)

Collapse
 
bias profile image
Tobias Nickel

how do you like using async/await functions? then you can avoid lots of the callbacks.

Collapse
 
eidorianavi profile image
EidorianAvi • Edited

Something like this?

router.post('/add-dog', async (req, res) => {
    const dog = new Dog({
        name: req.body.name,
        breed: req.body.breed,
    });

   try {
      const saved = await dog.save();
      res.json(saved)
   } catch(e){
     res.json(e);
   }
});
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bias profile image
Tobias Nickel

yes, and did you know, with the newer framework 'fastify' you can leave out the try catch block. and get some more advantages. while all the express middleware you are useing will still work.

Thread Thread
 
eidorianavi profile image
EidorianAvi

I've never heard of fastify. Sounds promising though. I'll be looking into that.

Thread Thread
 
bias profile image
Tobias Nickel

By the way, in my opinion there is nothing wrong with 'express' you can certainly build complete projects with it. My personal Website is still running on express.

But since IBM accuired the developers, express stopt progressing. That is also a good thing, because it is very stable.

backed by the OpenJS foundation, 'fastify' is also very stable.

I am giving lots of tips here, but I want to thank you for sharing this tutorial and hope you share more.

Thread Thread
 
eidorianavi profile image
EidorianAvi

I welcome any and all constructive conversation on coding! I'm always open to new ideas and have plenty to learn myself so I appreciate you checking out my post and also your knowledgeable input. Thanks Tobias.

Collapse
 
eidorianavi profile image
EidorianAvi

Are you talking about with the get and post requests? I'd love to see an example

Hey! Check out this week's Meme Monday post