This is part 3 of a series of posts which will show you how to create a RESTful API in Node.js.

For further reading please check out the following links:


Introduction

In the previous post, we deployed an instance of MongoDB with docker-compose and connected our application to it. We also created our Mongoose Schema and data Model.

In this post, we are going to implement the rest of the routes that are necessary to create a basic CRUD, as well as their respective database query functions.

These functions will make use of the model we created previously to query our MongoDB database.


The Coding Begins

Preview

As always, we will begin with a preview of how our directory will look by the end of this post:

PokeAPI part 3 directory tree

You may note that, directory-wise, nothing has changed since the previous post. Content-wise, however, there are quite a few changes.

Just as a reminder, to run our project we are currently using the following command:

npm run start

To start our dockerized MongoDB instance, use the following command:

docker-compose up

This said, let us begin.


PokeService: Querying the Database

It is now time to create our database query functions.

For this, as previously mentioned, we are going to make use of our Pokemon Model.

As our goal is to implement the four basic CRUD operations, the first function we are going to implement is one for reading the contents of the db.

Open up the pokemon.service.ts file, and type in the following:

As you can see, we’ve created a new function, named getAllPokemon. It uses the Pokemon Model to interact with MongoDB and find all the Pokemon in the db.

As Mongoose’s helper functions are extensively documented in the Mongoose docs, I don’t think it’s necessary to break them down here.

I will, however, comment on the guard clause inside the callback:

Guard clauses are, put simply, a check that exits the function, either with a return statement or an exception, in case of an error or fulfilled condition. They allow us to avoid unnecessary complexity (if else if structures) in our code.

This is our guard clause:

if (error) {
res.send(error);
}
res.json(pokemon);

By reversing the logic, and checking first for errors, we can avoid an else statement.

If any errors are encountered, we exit the function by sending the error. If we find no errors, then the Pokemon result is sent. We will make use of this technique throughout the rest of this post.


Implementing GET Routing

We now have our getAllPokemon function in our PokeService.

To be able to interact with this function, we must create another GET route.

Let’s open our controller, and add a new route:

As you can see, the endpoint to access this new route is “/pokemons”. (Excuse the glaring grammatical error, it’s to avoid confusion further on.)

From here on, I recommend using Postman to test our routes.

If all goes well, you should obtain output like the following from Postman:

Postman: Getting all Pokemon

As we haven’t introduced any data into our db, we are receiving an empty array. We have now completed our first db query successfully!


Adding a New Pokemon

Let’s implement a function to add a new Pokemon to our db.

Go back to the PokemonService and type:

To explain briefly, we create a Mongoose Document (newPokemon) from the request body and we save it into the db.

Note: Just as a reminder, Mongoose Documents are instances of Mongoose Models.

Let’s create the route to interact with our function.

In our controller:

Note that our new route is accessed through a POST request.

Head over to Postman, and add a new Pokemon to the db:

Postman: Adding a new Pokemon

If everything goes well, you should receive the Pokemon you just added as output.

To double-check, we can make use of our GET route:

Postman: Getting all Pokemon

As you can see, we now have a Squirtle in our db.

Don’t worry about the _id and __v fields. They are generated automatically by Mongoose, and we will deal with them later.


Deleting a Pokemon

To implement a function to delete a Pokemon, open up the PokeService, and type the following:

We obtain the ID of the Pokemon to delete from the request parameters, this is to say, the parameters in the query string in the URL to which we make the GET request.

It would look something like this:

localhost:9001/pokemon/123pokemonId

Mongoose has a very useful findByIdAndDelete helper function, which allows us to delete a Document (in our case, a Pokemon) by its _id field.

This function is shorthand for findOneAndDelete({_id: pokemonId}).

Note: If you have the need of deleting a document by any field other than _id, you may use the findOneAndDelete function mentioned before. More information about it here.

I’d now like to draw your attention to the following line:

const message = deleted ? "Deleted successfully" : "Pokemon not    found :(";

Here, we have a ternary expression which assigns a different value to the message variable, depending on the value of the second parameter (deleted) passed to the callback.

This is because Mongoose’s findByIdAndDelete function finds a matching Document, deletes it, and then passes the found Document (if any) to the callback.

Therefore, if Mongoose finds a Document, it will be deleted, in which case we return the Deleted successfully message. If not, we return the Pokemon not found message.

Once we have our function ready, let’s create our route.

In our controller:

In the route we have just created, we are indicating that we will receive a request parameter in the URL, a parameter we have named id. This is the parameter we previously used in the Pokemon Service to obtain the ID.

Note that this route is accessed through a DELETE request.

Once again, we open Postman, and test our new route by deleting the Squirtle (or whichever Pokemon you chose) we added to our db earlier:

Postman: Deleting a Pokemon

As you can see, we receive the Deleted successfully message.

If no Pokemon with the ID we specified were found, we would receive the Pokemon not found message instead.

We can double check that our Squirtle has been deleted correctly by obtaining all Pokemon from the db:

Postman: Getting all Pokemon

Empty array = no Pokemon = Squirtle has been deleted successfully.


Updating a Pokemon

In our Pokemon Service:

Note that we have used precisely the same technique as in the deletePokemon function: Obtaining the ID as a request parameter, using Mongoose’s findByIdAndUpdate helper function, and returning a message according to the value of the second callback parameter.

In our controller, let’s create the final route:

Considering that both the delete and put routes have exactly the same endpoint, we can chain them as shown above. This way, we don’t have to declare the same route twice, one for each verb.

Let’s head over to Postman, and test our final route. Don’t forget to add a new Pokemon, or you won’t have any data to update! I chose to add another Squirtle, which I will now update:

Postman: Updating a Pokemon

Let’s obtain all our Pokemon to check on our Squirtle:

Postman: Getting all Pokemon

Congratulations! Your Squirtle has evolved into a Wartortle, and you have successfully implemented all the basic CRUD functions and their respective routes.


Conclusion

In this post, we’ve learned how to query MongoDB by means of Mongoose Models and Documents. We have also implemented routes to access our CRUD functions.

If you’d like to see the full code for this post, you can do so here (branch “part3” of the PokeAPI project).

Thank you so much for reading, I hope you both enjoyed and found this post useful.

Better Programming

Advice for programmers.

Estefanía García Gallardo

Written by

Just a person who’s in love with computer sciences 💕💕 Developer of Npkill ~ https://npkill.js.org/

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade