This post is a sequel to Getting Started with MongoDB, Node.js and Restify. We’ll now guide you through the steps needed to modify your API by introducing Mongoose. If you have not yet created the base application, please head back and read the original tutorial.
In this post, we’ll do a deep dive into how to integrate Mongoose, a popular ODM (Object -Document Mapper) for MongoDB, into a simple Restify API. Mongoose is similar to an ORM (Object-Relational Mapper) you would use with a relational database. Both ODMs and ORMs can make your life easier with built-in structure and methods. The structure of an ODM or ORM will contain business logic that helps you organize data. The built in methods of an ODM or ORM automate common tasks that help you communicate with the native drivers, which helps you work more quickly and efficiently.
All of that said, the beauty of a tool like MongoDB is that ODMs are more of a convenience, as compared to how ORMs are essential for RDBMS’. MongoDB has many built in features for helping you organize, analyze and keep track of your data. In order to harness the added structure and logic that an ODM like Mongoose offers, we are going to show you how to incorporate it into your API.
Mongoose is an ODM that provides a straightforward and schema-based solution to model your application data on top of MongoDB’s native drivers. It includes built-in type casting, validation (which enhances MongoDB’s native document validation), query building, hooks and more.
Note: If you’d like to jump ahead without following the detailed steps below, the complete git repo for this tutorial can be found on GitHub.
PrerequisitesIn order to get up to speed, let’s make sure that you are all set with the following prerequisites:
- An understanding of the original API
- The latest version of Node.js (currently at v8.1.4)
- A Mac (OSX, macOS, etc. as this tutorial does not cover Windows or Linux)
- git (installed by default on macOS)
Getting StartedThis post assumes that you have the original codebase from the previous blog post. Please follow the instructions below to get up and running. I’ve included commands to pull in the example directory from the first post. With the third command above, you have successfully copied the initial codebase into its own directory, which enables us to start the migration. To view the directories on your system, use the following command: You should see the following output: Move into the new directory with the
New DependenciesWe’ll need to install additional dependencies in order to add the necessary functionality. Specifically, we’ll be adding mongoose and the mongoose-timestamp plugin to generate/store createdAt and updatedAt timestamps (we’ll touch more on Mongoose plugins later in the post). Since we’re moving away from the native MongoDB driver over to Mongoose, let’s go ahead and remove the dependency on the MongoDB driver using the following npm command: Now, if you view your package.json file, you will see the following JSON:
Mongoose Schemas & ModelsWhen you’re developing an application backend using Mongoose, your document design starts with what is called a schema. Each schema in Mongoose maps to a specific MongoDB collection. With Mongoose schemas come models, a constructor compiled from the schema definition. Instances of models represent a MongoDB document, which can be saved and retrieved from your database. All document creation and retrieval from MongoDB is handled by a specific model. It’s important to know that schemas are extremely flexible and allow for the same nested structure as the native MongoDB driver would support. Furthermore, schemas support business logic such as validation, pre/post hooks, plugins, and more – all of which is outlined in the official Mongoose guide.
In the following steps, we’ll be adding two schema definitions to our codebase and, in turn, we will import them into our API routes for querying and document creation. The first model will be used to store all user data and the second will be used to store all associated todo items. This will create a functional and flexible structure for our API.
Schema/Model CreationAssuming you’re inside of the root directory, create a new directory called models with a user.js and todo.js file: Next, let’s go ahead and modify our models/user.js and models/todo.js models. The model files should have the following contents:
models/todo.js Note: We’re using the mongoose-timestamp plugin by calling SchemaName.plugin(timestamps). This allows us to automatically generate createdAt and updatedAt timestamps and indexes without having to add additional code to our schema files. A full breakdown on schema plugins can be found here.
Route CreationThe /routes directory will hold our user.js and todo.js files. For the sake of simplicity, you can copy and paste the following file contents into your todo.js file and overwrite the previous code. If you compare the two files, you’ll notice there is a slight change in the way that we call MongoDB using Mongoose. Specifically, Mongoose is playing as a role of abstraction over our database model, piping operations to the native MongoDB driver with validation in between. Lastly, we’ll need to create a new file called user.js. Then create the routes/user.js file:
Our updated entry point for this API is in /index.js. Your index.js file should mirror the following:
Starting the Server
Now that we’ve modified the code to use Mongoose, let’s go ahead and run the npm start command from your terminal:
Assuming all went well, you should see the following output:
Using the APIThe API is almost identical to the API written in the "getting started" post, however, in this version we have introduced the concept of “users” who are owners of “todo” items. I encourage you to experiment with the new API endpoints using Postman to better understand the API endpoint structure. For your convenience, below are the available calls (cURL) for your updated API endpoints:
Note: The $PARAM_ID requirement in the URL denotes that the URL parameter should be replaced with a value. In our case, it will likely be a MongoDB ObjectId.
Final ThoughtsI hope this short tutorial on adding Mongoose to your API was helpful for future development. Hopefully, you noticed how using a tool like Mongoose can simplify writing MongoDB functionality as a layer on top of your API.
As Mongoose is only a single addition to keep in mind as you develop and hone your API development skills, we’ll continue to release more posts with other examples and look forward to hearing your feedback. If you have any questions or run into issues, please comment below.
In my next post, I’ll show you how to create a similar application from start to finish using MongoDB Stitch, our new Backend as a Service. You'll get to see how abstracting away this API in favor of using Stitch will make it easier to add additional functionality such as database communication, authentication and authorization, so you can focus on what matters – the user experience on top of your API.