DEV Community

loading...

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

EidorianAvi
My name is Adrian; currently a recent graduate of the Flatiron Software Engineering program. Broadening my knowledge base through posting and reading alike.
・5 min read

Review

Alright so where did we leave off last week?:

  • We talked about what a MERN application was and how Node, Express, and MongoDB made up the back-end.
  • We installed the necessary packages to get started.
  • We created a database on MongoDB.
  • We built out the root of the app and connected it to the database and set up its port.
  • We created a Model and its Schema.
  • We set up a GET and a POST request.

That wasn't so bad right? Now this week to flesh out our backend more I'd like to cover the variety of requests that generally make up a RESTful API such as GET, PUT/PATCH, POST, and DELETE and how to work with them in conjunction with a MongoDB database. I'd also like to demonstrate how to enable outside sources from pulling from our newly created API. Let's go.

HTTP REQUESTS

GET

So last week we set up a GET request to the root of our dogs page that simply returned a statement that we have arrived on the dog page. Not super useful to be honest. Let's expand on that.

GET all Dogs

Generally for an API if you're sending a GET to the root it will return all the resources. So we're going to set it up so it returns all dogs. Remember we're making our requests off of our router.

router.get('/', async (req, res) => {
   try {
       const dogs = await Dog.find();
       res.json(dogs);
   } catch(e) {
       res.json(e)
   }
});
Enter fullscreen mode Exit fullscreen mode

Now that should return an array of all of our dog objects stored in our database. I decided to go with async functions thanks to advice on my previous post. Let's break down the code a little bit.

  • Created an async get request to our /dogs route.
  • Created a try/catch block since it is an asynchronous function.
  • We can use Dog.find() to return all instances of dogs and this uses an await since it is in an async function and assigns it to a constant 'dogs'.
  • It then sends back a response in JSON format of the values now stored in the dogs constant.
  • If it is unable to do so it hits the catch and sends back a response in JSON format of the error.

Get one Dog

Okay so now that we set up a proper GET request to grab all dogs what if we want to grab only instance of a Dog? We can use its ID to pull just that from the database.

router.get('/:id', async (req, res) => {
    try{
      const dog = await Dog.findById(req.params.id);
      res.json(dog);
    } catch(e){
      res.json(e);
    }
 });
Enter fullscreen mode Exit fullscreen mode

Okay so let's cover what's different this time around.

  • We set up a query param in our route in the form of the id like so '/:id'.
  • We used findById on our Dog model.
  • We then passed in the request with the params of id.

Now time for a sanity check. Make sure to test out both get requests.

http://localhost:4000/dogs
Enter fullscreen mode Exit fullscreen mode

Should return all dogs.

http://localhost:4000/dogs/<id>
Enter fullscreen mode Exit fullscreen mode

Should return one singular dog based on the id you used in your param.

POST

Last week we had set up our POST request and you should have been able to successfully make one and it appeared on your database. I want to show you how that would look using an async function this time around it should do the same.

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

    try {
        const savedDog = await dog.save();
        res.json(savedDog);
    } catch(e) {
        res.json(e);
    }
});
Enter fullscreen mode Exit fullscreen mode

Last week we used callback functions and this time it's set up for an async function so we set up a try/catch block.

PATCH

Okay so now we have a dog in the database but what if something is misspelled or down the road something needs to be updated. That's what a PUT/PATCH is for.

router.patch('/:id', async (req, res) => {
    try {
        const updated = await Dog.updateOne(
            {_id: req.params.id },
            { $set: {
                name: req.body.name,
                breed: req.body.breed
            }}
        );

        res.json(updated);
    } catch(e){
        res.json(e);
    }
});
Enter fullscreen mode Exit fullscreen mode

What we did here:

  • Set up a query param to take in the id of the dog we are trying to update.
  • We used updateOne on our Dog model that takes in two things.
  • The first thing is an object specifying what we are finding it by in this case the _id of the dog. We can use the params of our request to pass into that.
  • The second thing we pass in is another object with $set as the key and the new object with updated info.

Go ahead and try to update one of your dogs and it should in turn send a response back with an update object.

DELETE

Lastly let's go over a DELETE request for when you need to simply remove something from the database.

router.delete('/:id', async (req, res) => {
    try {
        const deleted = await Dog.remove({_id: req.params.id})
        res.json(deleted);
    } catch(e) {
        res.json(e);
    }
});
Enter fullscreen mode Exit fullscreen mode
  • Sent an async DELETE request with an id for the query params.
  • Used remove on the Dog model and passed in our query param of id.
  • Sent a response back with a DELETE object to show that the delete has occured.

That one wasn't too bad right. Go ahead and try to delete one of your dogs by id now.

CORS

Okay so last thing to cover before wrapping up. At this point you should be able to make direct requests to your newly created API and get responses back no problem. What if you tried to perform say a fetch to the API from your react front-end at this point though? Not gonna happen. We have to allow for the resources to be shared to other applications before we can make requests to the API. Luckily that's super simple.

I may have fibbed a little when I said we had all the packages we needed installed in the last post. We need one more.

Run this in your CLI.

npm install cors
Enter fullscreen mode Exit fullscreen mode

CORS means Cross Origin Resource Sharing and allows for other applications to make requests to our API externally. Now that we have it installed lets just require it in our app.js just like we did with other packages.

const cors = require('cors');
Enter fullscreen mode Exit fullscreen mode

Now that we have that package in our application all we have to do is set up some quick middleware to enable it.

//Enable CORS

app.use(cors());
Enter fullscreen mode Exit fullscreen mode

You should be good to go to perform fetches on your node application from your front-end now.

Wrap Up

At this point you now have a fully functioning back-end. You have successfully created a RESTful API that you can make GET, POST, PUT/PATCH, and DELETE requests to. You have a database connected to store all the data. You are able to tap into the back end from your front-end application. Congratulations are in order.

That'll be it from this week. If anyone would like me to continue with Node posts feel free to reach out maybe I can do some AUTH or something similar in the near future. Anyways thanks for reading the post I hope you picked up a thing or two and as always happy coding!

Discussion (0)