This is part 2 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 set up our server and implemented our first GET route, which returned a lovely welcome message. As our goal is to perform basic CRUD operations on our Pokemon data, we need to have a database to store our information.

In this post, we are going to create and deploy a Docker container for our MongoDB database. We are also going to define our Pokemon data model using Mongoose.


Let’s Code

Preview

Once again, before we start, a little preview of how our directory tree will look by the end of this post:

PokeAPI part 2 directory tree

Just as a reminder: to run our project we’re currently using the following command:

npm run start

This said, let us begin.


Creating Our Docker-Compose File

The first thing we are going to do is create a docker-compose.yml file, on the same level as our src directory, which is to say, outside the src directory.

Once this is done, copy and paste the following code into the newly created file:

docker-compose.yml file

I’ll briefly explain what these configuration options mean:

  • version: Specifies the docker-compose version we are going to use.
  • services: We can specify a list of services which will be deployed with our container. In our case, we want a database, which is why we use the following attribute:
  • db: We indicate that we are going to deploy a database.
  • container_name: This is optional. It allows us to specify a custom container name. If we omit this option, a default container name will be generated.
  • image: Specifies the image that the container will be built from. In our case, the latest MongoDB image.
  • restart: Always restart the container if it stops. If it is manually stopped, it is restarted only when Docker daemon restarts or the container itself is manually restarted.
  • volumes: This is a very interesting option. It allows us to have data persistence. What does this mean? All of our data is going to be stored in a Docker container. However, Docker containers can be stopped, restarted, etc. In such cases, what happens to our data? Does it disappear? The answer is, it won’t disappear if we use the volumes option. We can specify a directory on our local machine where our data will be stored. In our case, this directory is named pokeData.
  • environment: We can specify environment variables. In our case, we are creating a database named Pokemon when the container starts.
  • ports: Specifies the ports that will be exposed (Host port: Container port). In our case, we are mapping our local port 27017 to the container port 27017 (27017 is the default port for MongoDB).

For more information about docker-compose files, you can check out this link.

Now that we have our docker-compose file ready, let’s start the container.

Fire up your terminal, and type this command:

docker-compose up 

If you’ve done everything correctly, you should be seeing output similar to this on your terminal:

docker-compose output

You should also see that a new directory named pokeData has appeared in your directory tree. This is the directory we specified earlier in our docker-compose file, by using the “volumes” attribute.

Our pokeData directory will store all our database data (once we insert some), and keep it safe and sound.

Isn’t Docker awesome and easy to use? A simple, intuitive, extensively documented configuration file and one command are all we need to have our database instance up and running. Beautiful.

Troubleshooting

If you’re getting the following output after executing the docker-compose up command:

ERROR: Couldn’t connect to Docker daemon at http+docker://localhost — is it running?

It means that your Docker daemon isn’t running. Execute this command to start the Docker daemon:

sudo systemctl start docker

And try the docker-compose up command again. The error should be gone.


Connecting Our App to Our Dockerized MongoDB Database

We have our database container deployed and running, so we now need to connect our application to it.

Open the app.ts file, and add the following code:

You may have noticed that, once again, we are hard-coding a variable: the Mongoose connection string.

To avoid this, let’s open our constants file, and store it there:

//src/constants/pokeAPI.constants.tsexport const PORT = 9001;
export const WELCOME_MESSAGE = "Welcome to pokeAPI REST by Nya ^^";
export const MONGO_URL = "mongodb://localhost:27017/Pokemon";

Back in our app.ts, we can now change the hard-coded string for our newly defined constant:

If we’ve done everything correctly, we should now be seeing the output below in our terminal where we ran our docker-compose up command.

If, for any reason, you stopped docker-compose previously, run the command again.

docker-compose terminal output

As you can see, our Docker container has accepted the connection we made from our application. So far, so good.


Creating Our Data Model

Now that we are connected to our database, we need a way to interact with it.

To achieve this, we are going to use Mongoose, which provides us with several data modeling tools, such as schemas and models. Mongoose makes interacting with MongoDB exceedingly easy and simple.

“Models are fancy constructors compiled from schema definitions. An instance of a model is called a document. Models are responsible for creating and reading documents from the underlying MongoDB database.” — Mongoose documentation

To store our data models, we are going to create a models directory in src, which will contain a file named pokemon.model.ts.

Inside this file, we are going to import Mongoose and create our data model:

Once we’ve created our Pokemon schema, we need to create a Mongoose model.

To do this, we will part from our newly created schema. Therefore, in the same file:

Note: I am fully aware of the fact that we are defining both our schema and model in the same file, a file named pokemon.model.

Despite being a control freak, I refuse to create two separate files for 10 lines of code. If you are even more obsessed than I am, you may, of course, create a separate file for your schema.

With our Pokemon model just created, it is now time to import it in the PokeService:

The Pokemon model will later be used to query our MongoDB database, once we create the CRUD routes and their respective db query functions.

This, however, we will leave for the following post.


Conclusion

In this post, we’ve learned how to deploy an instance of MongoDB with docker-compose, and how to connect our application to it. We’ve also used Mongoose to create both a schema and a model for our database.

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

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

In the following post, we will be implementing the rest of the routes that are necessary to create a basic CRUD, as well as their respective database query functions.

Here is the link to the next post:

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