Building A Basic API Using Express, Node, and MongoDB
Tags: javascript, node, mongodb, express
Published: 2020-08-25 02:25:05

Over the past week or two I have been trying my hand at learning MERN stack and building a simple tutorial project to play around in the code. For those that aren't familiar, MERN is an acronym for MongoDB, Express, React, Node, which happen to be the four technologies that make up the stack. I started by creating my back end API endpoints, using Express and Node to set up my server and MongoDB for the database. I'm going to break this down into a few different points so that you can hop back and forth if you already have some familiarity with any of the concepts/steps.



[1. MongoDB Setup](#mongodb-setup)
[2. Packages](#packages)
[3. Creating the Server](#creating-the-server)
[4. Models](#models)
[5. Routes](#routes)


#MongoDB Setup#

There are a few different ways to get your MongoDB database created and connected to your application. One of the main ways is by downloading MongoDB directly and creating the server on your own machine. A lot of developers do this, but for the sake of this project we are going to use [mongoDB Atlas](https://www.mongodb.com/cloud/atlas/lp/try2?utm_source=google&utm_campaign=gs_americas_united_states_search_brand_atlas_desktop&utm_term=mongodb%20atlas&utm_medium=cpc_paid_search&utm_ad=e&utm_ad_campaign_id=1718986498&gclid=CjwKCAjwyo36BRAXEiwA24CwGbtM6fpB8MyxWvhsuEIHx3K7Xq8yDy81yrrfZSphDGVSFlfVJMBmeRoCADQQAvD_BwE) since it is a quick and easy way to get things running. To get started, all you have to do is log in or create a free account. 

After logging in, create a new project by clicking the "New Project" button. Type in a name for your project and click the next button, and then on the next screen click the "Create Project" button. Next you will need to build the cluster for your project by clicking the "Build a Cluster" button and selecting the free shared clusters option. The last thing we will need to do is select a cloud provider and server location from the options provided. Personally, I chose AWS since they had the closest server to my location, but this part is up to personal preference. The other sections shouldn't need to be changed, but you can do things like change the cluster name as well if you would like. When you're happy with everything just click the "Create Cluster" button and wait while your cluster is being built. This can take 1-3 minutes so be patient if it takes a little while.

We won't be using this next section until we start building our server, so you can either grab the information now and set it aside until we need it, or just come back to this section once you start on the server. Either way, we now need to get what we need to connect our application to our newly created database cluster.

Go to your cluster and click connect. Here you will need to add an IP Address (current ip works fine if you're just using the machine you're working on) and create a user which we will use to connect in the next step. Click "Choose a connection method", and for this project we will select "Connect your application". If not selected already, choose Node.js as your driver and copy your connection string. This is what we will use in our server to connect to our database. It should look something like this: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lr7rwqycxzi2momtb45k.JPG)


#Packages#

Next I wanted to talk briefly about the packages we will be using. The first is obviously `express` which is a light web framework for Node.js that we will be using to help build our back end server. We will also be using `cors`, `dotenv`, `mongoose`, and `nodemon`. 

`cors` stands for cross-origin resource sharing and allows us to access resources outside of our server from our server. `dotenv` will make it easy for us to use a `.env` file to store sensitive variables such as our database username and password. `mongoose` will help make interacting with MongoDB in Node.js simpler for us. Lastly, `nodemon` will automatically restart our server for us whenever we make changes to our files.

Now that we have a quick overview, let's get everything set up. Navigate into your root backend folder and create your `package.json` file by using `npm init -y`.

Next lets install our dependencies by using `npm install express cors mongoose dotenv`. Lastly let's install `nodemon` globally by using `sudo npm install -g nodemon`

Now we're ready to start building our server!


#Creating the Server#

The first thing we will need to do is create our `server.js` file and require the files we will be using. I also include the code here to configure `dotenv` to allow us access to our `.env` file.


```javascript
// Require packages
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');

// Configure dotenv
require('dotenv').config();
```

Next we will create our server by assigning `express()` to an `app` variable and create a `port` variable that we will pass into `listen()` later to tell our app which port to listen on.


```javascript
// Middleware
app.use(cors());
app.use(express.json());
``` 

Here we just tell our app to `use` the middleware that we want.


```javascript
// Connect to mongoDB server
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, {useNewUrlParser: true, useCreateIndex:true, useUnifiedTopology: true});
const connection = mongoose.connection;
connection.once('open', () => {
    console.log("MongoDB database connection established successfully");
})

```

This code is connecting our server to our MomgoDB Atlas database. The `uri` variable will load our connection string that we got when setting up our cluster from our `.env` file. We pass that along with some object flags into mongoose's `connect` function. (the flags are to deal with depreciation issues) Lastly, we just have a console log that will run when the connection is open so that we know it worked.


```javascript
// Require and use Route files
const usersRouter = require('./routes/users');

app.use('/users', usersRouter);
``` 

Here, we are going to require and use our router files. If you include this before creating the files, it will cause an error so you may want to comment this out until we need it. Just know that this is how we include routes in our server. You can follow the pattern of:
`const <model-name>Router = require(<file-path>);` and then 
`app.use(<model-root-path>, <router-variable>);`


```javascript
// Server listen
app.listen(port, () => {
    console.log(`Server is running on port: ${port}`);
})
```

The last thing we need to do is tell our server which port to listen on which we do by passing our `port` variable into `app.listen()`. Here we also include a console log that will tell us which port our server is running on.


#Models#

Creating our models is rather simple. MongoDB is a document or noSQL database and so each instance of our example `User` model will be stored as a document similar to json. To create this model, we will add a `models` folder inside which we will create a `user.model.js` file. This is where we will be writing the schema for our database model. This is relatively straightforward so I will just post my code below and then explain it.


```javascript
const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const userSchema = new Schema({
    username: {
        type: String,
        required: true,
        unique: true,
        trim: true,
        minlength: 3
    }
}, {
    timestamps: true
})

const User = mongoose.model('User', userSchema);

module.exports = User;
```

So first we require `mongoose` and then create a `Schema` variable. We then declare a new variable `userSchema` which is a new `Schema` and pass an object into it. 

The keys in this object will be what properties we want for our model. In this case we only want our users to have a username to keep things simple. Each key's value will be another object that will specify our validations for the property. You can see that we want our `username` to be of type `String`, be required and unique, trim off excess white-space, and have a minimum length of 3. We also pass in a second object that specifies we want to model to also have a timestamp. MongoDB will automatically add indexes for us as well.

Lastly we pack everything up in a variable and export it.


#Routes#


Homestretch, we're almost there! The last thing we need to do is create the endpoint routes for our API. Create a new `routes` folder, and inside of it create a `users.js` file for us to work in.


```javascript
const router = require('express').Router();
let User = require('../models/user.model');
```

The first thing we will do in our file is require express router as well as our `user` model file.


```javascript
router.route('/').get((req, res) => {
    User.find()
        .then(users => res.json(users))
        .catch(err => res.status(400).json(`Error: ${err}`))
});
```

This is the code for our `/users/` route when our server receives a `GET` request. This implementation simple returns a list of all users if successful or an error code and message is it is not. You can easily edit this to include whatever functionality you wish.

The basic pattern here is calling `route` on `router` and passing in the desired route. Then we chain on the method for whatever request we want to handle (in this case `GET`) and then pass in a function that takes a `request` and `response` as arguments. These correspond to the request received by the server, and the response that it can send back after.

We are using the `find()` method on our `User` model to find all users in our database. This returns a promise which we handle with `.then()` and `.catch()`. If successful, we set our response to be the list of users we got as json. If not, we set the response to relay the error code and message.


```javascript
module.exports = router;
```

Lastly we export so that we can connect the routes to our server file. Remember that part I said wouldn't work until we had the file set up? That's this.

Using the route declaration pattern above, you can easily include more routes for different request types and routes. This is an example of what a `POST` request to add a user might look like.


```javascript
router.route('/add').post((req, res) => {
    const username = req.body.username;
    const newUser = new User({username});

    newUser.save()
        .then(() => res.json('User added!'))
        .catch(err => res.status(400).json(`Error: ${err}`))
});
```


#Conclusion#

That's really all there is to it. I know this guide is a bit lengthier than what I normally post, and there is definitely a lot of information, but if you are already familiar with building back end APIs using other stacks or frameworks a lot of this should look somewhat familiar. 

This is certainly a very simple overview, but I'm sure you can see how using the patterns explained above you could expand this into a more meaningful API that you could use to serve data to your front end React project. I hope you learned something new!


If you liked this post, feel free to follow me elsewhere on [Twitter](https://twitter.com/AJBanderas), [Github](https://github.com/kjdowns), or [LinkedIn](https://www.linkedin.com/in/kevinjdowns/). Happy Coding!