Welcome to this RESTful API using Node.js (Express.js) and MongoDB (mongoose) tutorial! We are going to learn how to install and use each component individually and then proceed to create a RESTful API.
REST stands for Representational State Transfer. It is an architecture that allows
client-server communication through a uniform interface. They are also
cachable and has property called
idempotence. It means that the side effect of identical requests have the same effect as the same single request.
HTTP RESTful API’s are compose of:
- HTTP methods, e.g. GET, PUT, DELETE, PATCH, POST, …
- Base URI, e.g.
- URL path, e.g.
- Media type, e.g.
Here’s is a summary what we want to implement:
|Resource (URI)||POST (create)||GET (read)||PUT (update)||DELETE (destroy)|
|/todos||create new task||list tasks||N/A (update all)||N/A (destroy all)|
|/todos/1||error||show task ID 1||update task ID 1||destroy task ID 1|
NOTE for this tutorial:
- Format will be JSON.
- Bulk updates and bulk destroys are not safe, so we will not be implementing those.
- CRUD functionality: POST == CREATE, GET == READ, PUT == UPDATE, DELETE == DELETE.
In this section, we are going to install the backend components of the MEAN stack: MongoDB, NodeJS and ExpressJS. If you already are familiar with them, then jump to wiring the stack. Otherwise, enjoy the ride!
MongoDB is a document-oriented NoSQL database (Big Data ready). It stores data in JSON-like format and allows to perform SQL-like queries against it.
You can installed following the instructions here.
If you have a Mac and brew it’s just:
After you have them installed, check version as follows:
The Node official definition is:
To install it, you can go to NodeJS Website.
Since Node versions changes very often. You can use the NVM (Node Version Manager) on Ubuntu and Mac with:
Check out https://github.com/creationix/nvm for more details.
Also, on Mac and brew you can do:
After you got it installed, check node version and npm (node package manager) version:
ExpressJS is web application framework that runs on NodeJS. Allows you to build web applications and APIs endpoints (mode details later).
We are going to create a project folder first, and then add
express as a dependency.
Let’s use NPM init command to get us started.
Notice that after the last command,
express should be added to package.json with the version
Mongoose is an NPM package that allows to interact with MongoDB. You can install it as follows:
If follow the previous steps you should have all you need to complete this tutorial. We are going to build an API that allow users to CRUD (Create-Read-Update-Delete) Todo tasks from database.
CRUD == Create-Read-Update-Delete
We are going to create, read, update and delete data from MongoDB using Mongoose/Node. First, you need to have mongodb up and running:
Keep mongo running in a terminal window and while in the folder
node to enter in the node CLI. Then:
Great! Now, let’s test that we can save and edit data.
If you take a look to Mongo you will notice that we just created an entry. You can easily visualize data using Robomongo:
You can also build the object and save in one step using
So far we have been able to save data, now we are going explore how to query the information. There are multiple options for reading/querying data:
- Model.find(conditions, [fields], [options], [callback])
- Model.findById(id, [fields], [options], [callback])
- Model.findOne(conditions, [fields], [options], [callback])
The result is something like this:
You can also add queries
You can chain multiple queries, e.g.:
MongoDB query language is very powerful. We can combine regular expressions, date comparison and more!
Moving on, we are now going to explore how to update data.
Each model has an
update method which accepts multiple queries, the first one is the find query and the second one is the update fields.
- Model.update(conditions, update, [options], [callback])
- Model.findByIdAndUpdate(id, [update], [options], [callback])
- Model.findOneAndUpdate([conditions], [update], [options], [callback])
Alternatively, the method
findOneAndUpdate could be used to update just one and return an object.
As you might noticed the batch updates (
multi: true) doesn’t show the data, rather shows the number of fields that were modified.
Here is what they mean:
nmeans the number of records that matches the query
nModifiedrepresents the number of documents that were modified with update query.
remove mongoose API are identical, the only difference it is that no elements are returned. Try it on your own ;)
- Model.remove(conditions, [callback])
- Model.findByIdAndRemove(id, [options], [callback])
- Model.findOneAndRemove(conditions, [options], [callback])
ExpressJS is a complete web framework solution. It has HTML template solutions (jade, ejs, handlebars, hogan.js) and CSS precompilers (less, stylus, compass). Through middlewares layers, it handles: cookies, sessions, caching, CSRF, compression and many more.
Middlewares are pluggable processors that runs on each request made to the server. You can have any number of middlewares that will process the request one by one in a serial fashion. Some middlewares might alter the request input. Others, might create log outputs, add data and pass it to the
next() middleware in the chain.
We can use the middlewares using
app.use. That will apply for all request. If you want to be more specific, you can use
app.verb. For instance: app.get, app.delete, app.post, app.update, …
Let’s give some examples of middlewares to drive the point home.
Say you want to log the IP of the client on each request:
Notice that each middleware has 3 parameters:
req: contain all the requests objects like URLs, path, …
res: is the response object where we can send the reply back to the client.
next: continue with the next middleware in the chain.
You can also specify a path that you want the middleware to activate on.
And finally you can use
app.get to catch GET request with matching route, reply the request with a
response.send and end the middleware chain. Let’s use what we learned on mongoose read to reply with a user data matching the
Notice that all previous middlewares called
next() except this last one, because it sends a respond (in JSON) to the client with the requeste
Hopefully, you don’t have to develop a bunch of middlewares besides routes, since ExpressJS has a bunch of middlewares available.
body-parser: parse the body so you can access parameters in requests in
cookie-parser: parse the cookies so you can access parameters in cookies
serve-favicon: exactly that, serve favicon from route
/favicon.ico. Should be call on the top before any other routing/middleware takes place to avoids unnecessary parsing.
The following middlewares are not added by default, but It’s nice to know they exist at least:
compression: compress all request. e.g.
session: create sessions. e.g.
app.use(methodOverride('_method'))Override methods to the one specified on the
GET /resource/1?_method=DELETEwill become
X-Response-Timeheader to responses.
errorhandler: Aid development, by sending full error stack traces to the client when an error occurs.
app.use(errorhandler()). It is good practice to surround it with an if statement to check
process.env.NODE_ENV === 'development'.
vhost: Allows you to use different stack of middlewares depending on the request
staticappare different express instances with different middlewares.
csurf: Adds a Cross-site request forgery (CSRF) protection by adding a token to responds either via
timeout: halt execution if it takes more that a given time. e.g.
app.use(timeout('5s'));. However you need to check by yourself under every request with a middleware that checks
if (!req.timedout) next();.
In the next sections, we are going to put together everything that we learn from and build an API. They can be consume by browsers, mobile apps and even other servers.
After a detour in Node CLI, MongoDB, Mongoose, tools and middlewares land we are back to our express todoApp. This time to create the routes and finalize our RESTful API.
Express has a separate package called
express-generator, which can help us to get started with out API.
This will create a new folder called
todo-api. Let’s go ahead and install the dependencies and run the app:
Use your browser to go to http://0.0.0.0:4000, and you should see a message “Welcome to Express”
In this section we are going to access MongoDB using our newly created express app. Hopefully, you have installed MongoDB in the setup section, and you can start it typing (if you haven’t yet):
Install the MongoDB driver for NodeJS called mongoose:
--save. It will add it to the
Next, you need to require mongoose in the
Now, When you run
npm start or
./bin/www, you will notice the message
connection successful. Great!
It is show time! All the above was setup and preparation for this moment. Let bring the API to life.
models directory and a
What’s going up there? Isn’t MongoDB suppose to be schemaless? Well, it is schemaless and very flexible indeed. However, very often we want bring sanity to our API/WebApp through validations and enforcing a schema to keep a consistent structure. Mongoose does that for us, which is nice.
You can use the following types:
I know you have not created any route yet. However, in the next sections you will. These are just three ways to retrieve, change and delete data from your future API.
If you open your browser and type
localhost:3000/todos you will see all the tasks (when you implement it). However, you cannot do post commands by default. For further testing let’s use a Chrome plugin called Postman. It allows you to use all the HTTP VERBS easily and check
x-www-form-urlencoded for adding parameters.
Don’t forget to check
x-www-form-urlencodedor it won’t work ;)
Probably this is the main consumers of the APIs. You can interact with RESTful APIs using jQuery’s
$ajax and its wrappers, BackboneJS’s Collections/models, AngularJS’s
$resource, among many other libraries/frameworks and mobile clients.
In the end, we are going to explain how to use AngularJS to interact with this API.
To sum up we want to achieve the following:
|Resource (URI)||POST (create)||GET (read)||PUT (update)||DELETE (destroy)|
|/todos||create new task||list tasks||error||error|
|/todos/:id||error||show task :id||update task :id||destroy task ID 1|
Let’s setup the routes
app.js add new
todos route or just replace
All set! Now, let’s go back and edit our
Remember mongoose query api? Here’s how to use it in this context:
Harvest time! We don’t have any task in database but at least we verify it is working:
If it returns an empty array
 you are all set. If you get errors, try going back and making sure you didn’t forget anything or write a comment at the end of the post for help.
routes/todos.js, we are going to add the ability to create using mongoose create. Could you make it work before looking at the next example?
- We are using the
- You have to stop and run the server again:
Everytime you change a file you have to stop and start the web server. Let’s fix that using
nodemon to refresh automatically:
This is a snap with
req.params. Notice that
params matches the placeholder name we set while defining the route.
:id in this case.
Let’s test what we have so far!
routes/todos.js, we are going to update tasks. This one you can do it before looking at the example bellow, review findByIdAndUpdate and give it a try!
Finally, the last one! Almost identical to
Is it working? Cool, you are done then! Is NOT working? take a look at the full repository.
Connecting AngularJS with this endpoint. Checkout the third tutorial of this series.