Build a REST API with Node, Express MongoDB & Postman!
Tags: node, express, mongodb, api
Published: 2020-10-26 02:41:37

In this project, we will be creating a simple API that would allow people Update, Delete, Create, and Subscribe to a social media account. We will do this by coding the data the users will be interacting with within our social media database and how it goes about manipulating them depending on what a user wants to do.

##Project Requirements and Dependencies
**Important Prerequisite:** Make sure you already have MongoDB installed and set up on your machine before starting this tutorial. Here is a link to a guide that MongoDB provides on their website: [MongoDB Installation](https://docs.mongodb.com/manual/administration/install-community/)

After installing MongoDB, the next step would be the opening of your command line, then create a new directory for the project we will be working on using this command `mkdir directory_name` this would quickly create your new directory, then you would need to be in the newly created directory by using the following command `cd directory_name` this would give you access to the directory you have created.

In this project, we would be working with the `express generator` to quickly create our application skeleton. For earlier Node versions, install the generator as a global npm package and then launch it using the following command `npm install -g express-generator`. This would automatically install the `express generator` globally on your local machine, after installation, you would be required to type `express` in your command line, this will create all the required files to set up your express app skeleton

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

After creating our express app, you would be required to delete the `views and public` folders as well as the `bin` folder, since all we are creating is a simple REST-API, we won't be needing to make use of them, also, we will be required to take out the line of codes for the view engine set up and the middleware for joining the public directory to our app.js file.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/585wlyz0m4mzehgw4cwo.PNG)

Next, we will be installing [Mongoose](https://mongoosejs.com/), which connects our application to the MongoDB Database using this command `npm install mongoose` then `dotenv and nodemon` for setting up our environment variables and restarting our local server respectively, after we saved our files with the `.JS` extension. this will be installed using the following command `npm install --save-dev dotenv nodemon`.
*Note: --save-dev from above will save development-only dependencies without saving them to production*

`dotenv` will allow us to pull in environment variables from a `.env` file. When we ran the `express` command earlier it created a `package.json` file. In this file under the scripts, we want to replace that ‘test’ script with our own script that starts our server with `nodemon`:

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

#Setting up Our Local Server
Running the `express` command in the command line, after installing `express-generator` automatically created an `app.js` file. Once created, we will need to require all our packages at the top of our `app.js` file, for the file created using the `express` command, you will already have the express dependency declared at the top of the `app.js` file, all you will need to do is require the `dotenv and mongoose` packages.

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

When we want to test and make sure our server is working, we will run this function to listen on port 3000 and log a string if it's successful: 

`app.listen(3000, () => console.log('server started'))`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0kwkktxgiv4jzaoc4ulw.PNG)

#Connecting to Our Database
Before running the database connection, first, you will be required to pull in the `dotenv` package you had initially installed, just the same way you did for express and mongoose like this `const dotenv = require('dotenv').config()`. The `.config()` function automatically configures the `dotenv` package to be used in your application entry point.
This next chunk of code in our `app.js` file starting with `const CONFIG` is how we will be connecting to the database. I’ll explain it line by line:

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

The `OPTIONS` object is actually optional for the purpose of this API, `mongoose.connect(CONFIG.uri, CONFIG.OPTIONS)` allows us connect to the database, you may be wondering the `DATABASE_URL`, this is the location where we want to store our database, which has been identified in the `.env` file created in the root folder of our API. If you haven't created a `.env` file, now will be a good time to go about this and set the `DATABASE_URL` there:

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

Moving on, we have to set `db` to `mongoose.connection` as a syntactically easier way to reference our database. Next, we’ve defined what happens when the database connection is successful, which is to log the string of connection to the database on our terminal.

#Testing the Database Connection
At this point, we can now test out our connection to the database to make sure everything is working smoothly. In our terminal, let’s go ahead and start our database by typing mongod and then in another terminal tab let’s start our server with `npm run dev`. If all went well, we should get these messages after we start our server:

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

Cool! We’ve successfully started our server and our database appears to be operational.

#Setting up our Server to Accept JSON
In our same app.js file we want to tell `Express` that it should accept JSON. Lets put this line of code in between our ‘database is open’ line of code and the ‘listen on port 3000’ line:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7f6mqafsdgepjsff16e4.PNG)

The `.use` is a middleware that allows you to run code when the server gets a request but before it gets passed to your routes. So in this instance, we’re telling `Express` to accept JSON as the data format.

#Creating our Route File
Inside our directory, you will notice you already have a `routes` folder in it, we also have an `index.js` file, this is where we will define how the server should handle the data when it receives a GET, POST or PATCH/UPDATE request.
But before we start creating those, let's switch back to our app.js file and tell the server that we now have routes that it needs to handle and use. These next two lines of code are actually the last ones we need for our app.js file.
`var indexRouter = require('./routes/index');`
`app.use('/', indexRouter);`

Here’s the full server.js file with the new lines of code added:

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

If something is missing or incorrect, right now is a great checkpoint to make sure you’ve got everything updated with the above. Give yourself a pat on the back for getting this far! We’re getting onto the fun stuff next…

#Setting up Our Routes
Now that our server file is all set up, we will now switch gears to our new `index.js` routes file. To start, let us require `Express` and define the `express.router()` function on a variable called router. While we’re at it let’s add our module export function as well at the very bottom:

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

Before we get into the code, let’s get an understanding of what we exactly want to do with our routes. Since we’re trying to see and artificially create new subscribers on Social App, we need this set of criteria:

`Route for getting all subscribers
Route for getting one subscriber
Route for creating one subscriber
Route for updating one subscriber
Route for deleting one subscriber`

Now let’s start each of the bullet points above with the basic framework depending on if its a GET, POST, or PATCH request:

To get this fully set up, we could be creating this API using the MVC method without a `View`, by this, I mean since it's just an API we won't be needing to render page here. We will be creating a `Controller` folder which will handle all of our routing functions, then we will be exporting these functions to our `index.js` file in the `Routes` folder. First, you should have these lines of code in your `index.js` folder for your routing.

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

Ignore all the errors, for now, we will sort out all of those very soon, you may go ahead in creating your controller folder and an `indexController.js` file.
The one thing that might look weird is the PATCH method. The PATCH method is being used here instead of the more traditional PUT method because we only want to use this to update pieces of the subscriber’s information and not all the information of the subscriber.
You also may have noticed that we include `/:id` in most of our parameters. This is for the routes that are requesting an action to be taken on a single subscriber thus we need that subscriber’s unique ID.

#Testing Our IndexController File
In our `indexController.js` file we will be writing a chunk of code, this is with the aim of testing our API to see if it's well connected using our routing. I will be needing to explain the code below, later on, right now our routing functionality is now been declared in the `indexController.js` file then export to the `index.js` file in the router folder

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1n03vsb6f6kxnrjw47v7.PNG)

Below is where the `indexController.js` file is being imported into the routing file.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/223lfxag4ua7u0ui21mn.PNG)

What the above block of code means is this, in the `indexController.js` file, we used a class-based method in exporting all our functions, then we created an arrow function called `testingRoute` then assigned a response and require argument to it, afterward, we sent a simple JSON message `'Hello World'` using the `res.send()` command in a try and catch block. What this does is to try the initial command in this function, in case there is an error, the catch block prints the error in the console, after this is done, we then export the functions inside the `Class` to the router file.
In the `index.js` file we then require the `indexContoller.js` file and assigned it to a new variable called `IndexController`,  then using the `GET` method, we will be calling out the content of the `indexController.js` as shown in the code above.

Now for testing our API, I will be making use of Postman, you can download it from their official page [Postman Installation](https://www.postman.com/downloads/). After you are done installing, open the Postman app, you will get the same page:

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

All you will be required to do is test the GET call to our Server
`http://localhost:3000` using the Postman app, just click on the `+` icon on the app to access a new tab, then copy this URL and paste in the input field, first you need to select the action as a GET request, then hit the Send button, this would print the `'Hello World'` text we sent through the `indexController.js` file as shown below: 

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

This means our API is working correctly! Ok so we’ve done a lot so far, let’s take a hydration break, and then we’ll get started with models.

#Making the Models
Let’s go ahead and set up our model and the schema inside of our model. A schema is how our app defines what the data looks like and also sets up the document in MongoDB. If that sounds confusing, it’ll make more sense once we see what’s going on.

Let’s first start by creating a new folder called models. Inside of this folder, let’s create a new file called subscriber.js. The idea is that the model will handle how each and every subscriber, on an individual level, will look inside of our database. The ‘index’ routes handle sometimes multiple subscriber's requests such as Get All Subscribers route. It’s an important thing to mention as verbiage is important when naming files in projects.
In this new file, we want to first require Mongoose since we will be using their schema models:
`const mongoose = require('mongoose')`
After we require mongoose, we’ll start by defining our schema
`const mongoose = require('mongoose')`
`const subscriberSchema = new mongoose.Schema({})`

Inside of this javascript object will be all of the keys for the different properties of our subscriber. These keys will include `name, subscribedChannel and subscribeDate`. We essentially want to tell our database what to expect from each one of these keys such as their type, if they’re required and if a default value should be applied.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8buydue0g1qaxoevvoyb.PNG)

The type and required properties should be pretty self-explanatory. These are defining the expected schema type (a String and Date in this case) as well if that key is required upon entering information for a new subscriber.

One thing to note about `subscribeDate`, we set the type to Date instead of String since we will be expecting a date from the user. If no date is provided then we default it to the current date by using `Date.now`.

Moving on, the last line of code we want to write in our schema is the module.exports. This will allow us to use and interact with the database using our schema. Mongoose has a special way of exporting models utilizing mongoose.model() that takes two properties:

`module.exports = mongoose.model('Subscriber', subscriberSchema)`
‘Subscriber’ is the name we want to give the model in our database and then the next one is the schema that corresponds to that model which is our subscriberSchema.

That’s it for our model! Let’s take a look at the finished schema to make sure we’ve got it all:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5i8ag0yxlxht4e6iohzi.PNG)

#Creating and Getting Subscribers
Now that we have our model setup with a schema for our database, let’s require it in our indexController.js controller file below where we required router
`const Subscriber = require('../models/subscribers')`

We have our test response from earlier when we sent ‘Hello World’ to the server but we can go ahead and delete that since we want to actually tell that route to Get All Subscribers.

The first thing we’ll need to do after we get rid of our old res.send('Hello World') line in the `indexController.js` file, is wrap the function in a promise with a try/catch statement, just like we already did previously:

Inside of our try statement we want to get all of the subscribers from our model. So we want to set a new variable called subscribers to that model with a .find() method applied to our Subscriber model.

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

As the name implies, the find() Mongoose method works by returning all associated subscriber objects that meet its criteria. Since we’re returning all subscribers, we just leave the parentheses blank since we want all the subscribers:

After that line, we then want to send a response with the data of our subscribers variable we just created in the form of JSON. Finally, in our catch statement we want to just catch any errors that may occur and have it sent to the user as a 500 error in JSON format:

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

Now that we have our route to send us all the subscribers in our database, we need to code a way for us to actually add a subscriber into our database. So, lets move onto our Create One Subscriber controller so we can enter data about a subscriber:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0v7akztql6kdl8in0uqy.PNG)

You can see it's somewhat similar to our Get All Subscribers controller except for a few important differences. For one, we’re no longer doing a GET call on our database but a POST which will allow us to push data to our database.

On this line:

`const subscriber = new Subscriber({...`

we are creating a variable that will be assigned to a new Subscriber from our model that we created earlier. If you recall, we require a `name, subscribedChannel and subscribeDate` properties for a new subscriber.

These next two lines of code:

`name: req.body.name,
subscribedChannel: req.body.subscribedChannel`

We’re telling our controller to save the request made from a user’s input of a new Subscriber name property and `subscribedChannel` property. Our subscribeDate doesn’t need to be defined because it will default automatically to the date/time that this database entry is made.

The `try and catch` statements should look familiar. We’re instead using a `.save()` Mongoose method instead of `find()` because this is how we will tell the database that we want it to hold the information a user passes to us through this controller function.

Lastly:

`...
res.status(201).json(newSubscriber)
} catch (err) {
res.status(400).json({ message: err.message })
}`

We’re sending the user response with a success status of 201 and to pass our new subscriber back to us as JSON. The catch is just like our Get All Subscribers controller except we pass a 400 error since this would be a user error for passing us bad data.

To test all of this, in our `index.js`route file, after requiring the `indexController.js` file, for the Get all Subscribers route, this would be written out like this `router.get('/', IndexController.getAllSubcribers)` since it is a get request to all the Subscribers, for the create a single Subscriber, since it is a POST action `router.post('/create', IndexController.createSingleSubcriber)`, mind you at this point you have your IndexController called up in the `index.js` file like we do in the code below:

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

`...
IndexController.getAllSubcribers and 
IndexController.createSingleSubcriber`

This is just a way of targeting the functions inside the `indexControler.js` file, remember we recently declared these two functions to get all subscribers and create a single subscriber, we do this by appending the functions of the `indexController.js` file to the `IndexController` variable which was declared in the route file `const IndexController = require('../controller/indexController')`.

Now to actually test all we have done, we will be create a new subscriber using the `create` route we just created, remember it is a POST action. we will do this by typing the following url in our Postman application. `http://localhost:3000/create`, the `/create/ path was declared in our `index.js` route file. Before hitting the create route, we need to do a quick set up in Postman to be able to pass in raw JSON data

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

First, we need to select the `Body(in green)`, then the raw option, afterward we then select JSON from the drop-down option, this would make POSTMAN know we are about passing a JSON data,
Once you do this as shown above you can then manually type this in the same format in the input space provided in POSTMAN
` {
  "name": "Robert",
  "subscribedChannel": "Bennetts Channel"
} `
If after you are done with this and hit the submit button, you should get this output:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3n2bzto8iewow04prlcy.PNG)

We just created a new user, the user now has his own unique ID, If everything went well, our response when we click ‘Send Request’ should look like the above. We can see that we received our 201 success status at the very top along with our Subscriber object at the bottom with all the information we just plugged in.

Again, subscribeDate is set automatically to the date of creation so we don’t need to manually set it.

At this point, we can easily get the number of subscribers in our database by just hitting the `http:localhost:3000/` URL, but this time with a GET action, after hitting the send button, POSTMAN would print out all SUbscribers in the Database.

#Get Single User
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kpqo2zdvx2dli5r1z5dv.PNG)

The first line on this code looks pretty familiar already, in the `try and catch` block, we used a MongoDB method of `findById` to target a particular ID from our Database, where `(req.params.id)` The req.params property is an object containing properties mapped to the named route “parameters”. For example, if you have the route /student/:id, then the “id” property is available as req.params.id. This object defaults to {}. Now, we are mapping through the Subscriber Database to search for a particular ID,`findUser == null` implies that if the subscriber is not in the Database, the next command in the function is to return a status code of `Error 404` with the message of `'Cannot find the subscriber'` else `res.status(201).json(findUser)` simply implies that the subscriber found should be printed in JSON with the status code of 201, which means that everything is working well.
At this point your `index.js` route file should be looking like this:

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

To get a single Subscriber, we need to first GET all the Subscribers, using the URL `http:localhost:3000/` in your POSTMAN, then copy a Subscriber's unique ID, after doing this you can now confirm if your function is working well by hitting this link `http:localhost:3000/single/theUserId` this should get you the single User with the status code of 201.

#Delete Subscriber

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

Just the same way we did for the GET single Subscriber by using the MongoDB command of `findById`, in this case, we had to do a little different thing, after finding the users by their ID using `const findUser = await Subscriber.findByIdAndDelete(req.params.id)` the next action was confirmed is the User/Subscriber really exist in the Database, if so, remove this user using the following command `Subscriber.remove()` where Subscriber is the model the user is located and remove() is a MongoDB function to remove a data from the database, after you are done, your code should look just like what we have above, if the subscriber is not in the Database, the next command in the function is to return a status code of `Error 404` with the error message. After this has been done successfully, your delete route in the `index.js` route file should and update and would look like this:

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

Also if you try deleting a Subscriber, after selecting their ID on POSTMAN, you should get this result too:

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

--NB: This has got to be a DELETE action also like you did for GET to get all Subscribers or single Subscriber--

#Patch/Update a Subscriber
Our Update Subscriber route is the very last thing we need to write for this application to be fully functional! Ok so before we get into the code lets get a general idea of how updating will work in this case:

User updates just the name
User updates just the channel
User updates both name and channel
Or they mess up and it throws an error
Our requirements need for us to essentially check and see if any changes were made and if so, update them appropriately. Now onto the code:

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

Using the same method as wit the previous, the first line of code remains familiar, 

`...
const updateUser = await Subscriber.findByIdAndUpdate(req.params.id , {
            name : req.body.name,
            channel : req.body.subscribedChannel
        }`
In this case, we are using a method of findByIdAndUpdate, to map through the Database, and then if the particular that has been inputted is actually in the Database if so, we are targeting the `name and subscribedChannel` from the `Subscriber` model, and either update both fields or any one of them, if this operation is okay, print the `JSON` message. 
If your code is correct and is the same as the one above, the next operation would be updating your `index.js` route file, which would finally look like this:

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

Afterward. we can now test this route with the POSTMAN. first, we will get a single user using his Id and this link,`http:localhost:3000/single/5f967dedbab34829a4eb83ee`. this will be a GET request, after we get this User, and update his/her record, we can then PATCH the user using this URL `http:localhost:3000/update/5f967dedbab34829a4eb83ee` and his the Send button, we will get the result below:

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

You can confirm that the User details really got updated by either get just that user again or getting all the users as shown below:

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

#Conclusion
Guys, we made it. I really hope this tutorial was helpful to some of you. We went over a lot of stuff so if you’re feeling overwhelmed then that's totally understandable. But realize we just made a pretty awesome backend piece of code that translates into so many different real-world applications. So big props to you for making it through it all!

The complete code can be found in the Master branch of my [GitHub repo](https://github.com/staunchCFO/simple-API.git)

If you ever got stuck or found something worth mentioning, go ahead and drop a message on [Twitter](https://twitter.com/staunchCFO) or leave me a comment below.