Node REST API - Part VII
Route my calls :-)
Routes are nothing but http URLs. In REST routes are referred to as end points. In Part V of this series we defined a simple route.
router.get('/api', routes.welcomeAPI);//api end point
We need to implement a welcome message for our API. A message that will say something about our API. Let's create a new file called routes.js under the api folder. Right click on the api folder and click New File. Save this file as routes.js.
Now we will implement routes.welcomeAPI
/**
* welcomeAPI()
* @Request GET
* Root API route message
*/
exports.welcomeAPI = function(req, res){
res.json({message:'Welcome to Recipe API!'});
}
Very simple. It's a GET request.Upon making a request to localhost:3000/api our express server will return a simple message "Welcome to Recipe API!". You see how easy it is to implement routes?
Now we are ready to turn on the express server and have some fun.Go to the express-api directory in the terminal or a command line. Enter the command below.
node .
Calling node . will run index.js file. Simple, right? Remember to put a space between node and a . (dot).
If you have a file called server.js then run,
node server.js
If express server is started successfully then you will see a message Express Server running
With welcome route in place, now let's define and implement POST, PUT, DELETE & GET routes.
Moving back to mongoose models, we will focus on RecipeTypes model. Let's review our recipe type document & a mongoose model one more time.
[
{
"_id": 1,
"recipe_type": "Italian"
},
{
"_id": 2,
"recipe_type": "Indian"
},
{
"_id": 3,
"recipe_type": "Thai"
},
{
"_id": 4,
"recipe_type": "Mexican"
}
]
We took this document and created our mongoose model. Here is the code for mongoose model.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var recipeTypeSchema = new Schema({
"_id":Number,
"recipe_type":String
});
module.exports = mongoose.model('RecipeType', recipeTypeSchema);
For the detailed explanation on mongoose modeling review Part VI of this tutorial series. At this point we do not have any recipe type saved in the database. In other words, our MongoDB document is a clean slate. Before we look at how to select, update and remove data: we need data. Right? So let's create some recipe types using the POST route.
POST Route
Let's create a route definition in our index.js file.
router.post('/api/recipetype', routes.createRecipeType);//create a new recipe type (POST)
We need to create new recipe types. What this means is we have to post data through express server. Quite obviously this will be a post route. Notice routes.createRecipeType? This is the route function. When an application or a user posts data to localhost:3000/api/recipetype URL, the routes.createRecipeType function is called. This function will retrieve posted data and insert this data into MongoDB document via Mongoose model.
Here is the implementation of routes.createRecipeType.
/**
* createRecipeType()
* @Request POST
* Creates a new Recipe Type
*/
exports.createRecipeType = function(req, res){
if(req.body.recipe_type){//if recipe_type passed in the request body
//count for the same recipe type
RecipeType.count({recipe_type:req.body.recipe_type}, function(err, count){
if(err) console.log('Error counting recipe types');
//if recipe type exists then return
if(count > 0){
res.json({message:'Recipe type exists! Please try another recipe type'});
}else{
//add new recipe type
RecipeType.create(req.body, function(err, recipetype){
if(err) console.log('Error saving recipe type');
res.json(recipetype);
});
}
});
}
}
Let's review this code. We are checking to see if the request body has a new recipe_type. Next we want to make sure we are not inserting the same recipe_type again, right? After all this document is like a reference table. And therefore we check to see if this new recipe_type exists in the database.We count records for this new recipe_type. If count returns 0 then we insert new recipe_type in the RecipeTypes collection.
Pay attention to the code that inserts new recipe_type in our RecipeTypes collection.
RecipeType.create(req.body, function(err, recipetype){
if(err) console.log('Error saving recipe type');
res.json(recipetype);
});
In the code above we are referring to RecipeType model and passing entire request body req.body. Our callback function confirms the status. If error inserting data then it will log the errors in the console else it will return the newly created recipe_type. Simple, right?
I will use Chrome REST client to test and create few recipe types. Here is our post request. Notice how I am calling "localhost:3000/api/recipetype" and along with I am also passing "recipe_type" of "Indian".
After clicking "Send", here is the response received from node server.
And Voila! Now our MongoDB shows the new recipe type.
I will create few more recipe types using the REST client and as you see below, now we have all recipe types in the MongoDB document now.
Now let's look at how we select this data using a route.
GET Route
Let's define a GET route in index.js file.
router.get('/api/recipetypes', routes.getRecipeTypes);//recipe types listing end point
It is a GET request. This route will call routes.getRecipeTypes function and display all recipe types from our collection. Here is the implementation of this function.
/**
* getRecipeTypes()
* @Request GET
* Returns Recipe Types Listing
*/
exports.getRecipeTypes = function(req, res){
RecipeType.find(function(err, recipetypes){
if(err) console.log('Error querying recipe types collection');
res.json(recipetypes);
});
}
We are executing find(callback) on the RecipeType model. Callback function processes the data returned by the find() function. Let's test the GET route using the REST client.
Simple GET request. Notice how we use the Route and the GET option. Sending request to express server it returns the response as below. Sure enough we have listing of all recipe types from MongoDB document.
PUT Route
This is actually our update route. With a PUT route we can update existing data in MongoDB. In this case let's modify recipe type Indian to Spicy Indian. My roots are in India & I love spicy food. First we need to define a PUT route in index.js file.
router.put('/api/recipetype/:recipe_type', routes.updateRecipeType);
And below is the implementation of routes.updateRecipeType function.
/**
* updateRecipeType()
* @Request PUT
*/
exports.updateRecipeType = function(req, res){
if(req.params.recipe_type){
RecipeType.count({recipe_type:req.params.recipe_type}, function(err, count){
if(err) res.json({message:'Error updating recipe type'});
if(count > 0){
RecipeType.update({recipe_type:req.params.recipe_type}, {recipe_type:req.body.recipe_type}, function(err){
if(err) res.json({message:'Error updating recipe type'});
res.json({message:'Recipe type updated successfully!'});
});
}else{
res.json({message:'Recipe type not found'});
}
});
}
}
In the code above we are simply checking for the existing record, if the record exists then update the RecipeType document with new recipe type. Let's test the PUT route using the REST client.
And here is the updated record in MongoDB collection.
DELETE Route
You guessed it right. This route is used to remove selected records from a MongoDB collection. Let's add a route definition to index.js file.
router.delete('/api/recipetype', routes.deleteRecipeType);
And below is the implementation of the routes.deleteRecipeType* function.
/**
* deleteRecipeType()
* @Request DELETE
* Removes a specific recipe type
*/
exports.deleteRecipeType = function(req, res){
if(req.body.recipe_type){
RecipeType.remove({recipe_type:req.body.recipe_type}, function(err){
if(err) res.json({message:'Error removing recipe type'});
res.json(req.body.recipe_type + " removed successfully!");
});
}
}
In the code above, we check to see if user has specified the recipe_type to be removed. If so move forward and execute remove(query, callback) on RecipeType document. Our query finds the recipe_type in MongoDB collection and removes it. Callback function notifies us with corresponding JSON message. Let's remove the "Mexican" recipe_type using the REST client.
And now here is what the MongoDB collection looks like. You notice, "Mexican" recipe_type is not in the list anymore.
Easy, right?
Index JS Route Definition & A Complete Routes.js
Routes should look like below in the index.js file.
router.get('/api', routes.welcomeAPI);//api end point
router.get('/api/recipetypes', routes.getRecipeTypes);//recipe types listing end point
router.get('/api/recipetype/:recipe_type', routes.getRecipeType);//retrieve specific recipe type end point
router.post('/api/recipetype', routes.createRecipeType);//create a new recipe type (POST)
router.put('/api/recipetype/:recipe_type', routes.updateRecipeType);
router.delete('/api/recipetype', routes.deleteRecipeType);
Complete Routes.js fie is as below.
'use strict';
var RecipeType = require('./model/recipetype.model');
/**
* welcomeAPI()
* @Request GET
* Root API route message
*/
exports.welcomeAPI = function(req, res){
res.json({message:'Welcome to Recipe API!'});
}
/**
* getRecipeTypes()
* @Request GET
* Returns Recipe Types Listing
*/
exports.getRecipeTypes = function(req, res){
RecipeType.find(function(err, recipetypes){
if(err) console.log('Error querying recipe types collection');
res.json(recipetypes);
});
}
/**
* createRecipeType()
* @Request POST
* Creates a new Recipe Type
*/
exports.createRecipeType = function(req, res){
if(req.body.recipe_type){//if recipe_type passed in the request body
//count for the same recipe type
RecipeType.count({recipe_type:req.body.recipe_type}, function(err, count){
if(err) console.log('Error counting recipe types');
//if recipe type exists then return
if(count > 0){
res.json({message:'Recipe type exists! Please try another recipe type'});
}else{
//add new recipe type
RecipeType.create(req.body, function(err, recipetype){
if(err) console.log('Error saving recipe type');
res.json(recipetype);
});
}
});
}
}
/**
* updateRecipeType()
* @Request PUT
*/
exports.updateRecipeType = function(req, res){
if(req.params.recipe_type){
RecipeType.count({recipe_type:req.params.recipe_type}, function(err, count){
if(err) res.json({message:'Error updating recipe type'});
if(count > 0){
RecipeType.update({recipe_type:req.params.recipe_type}, {recipe_type:req.body.recipe_type}, function(err){
if(err) res.json({message:'Error updating recipe type'});
res.json({message:'Recipe type updated successfully!'});
});
}else{
res.json({message:'Recipe type not found'});
}
});
}
}
/**
* deleteRecipeType()
* @Request DELETE
* Removes a specific recipe type
*/
exports.deleteRecipeType = function(req, res){
if(req.body.recipe_type){
RecipeType.remove({recipe_type:req.body.recipe_type}, function(err){
if(err) res.json({message:'Error removing recipe type'});
res.json(req.body.recipe_type + " removed successfully!");
});
}
}
You saw how we used GET route to retrieve a listing of recipe types. But how about retrieving a specific recipe type. You guessed it right. Use the GET route to accomplish that. How? Well, since now you have mastered REST API routes, how about a little exercise for you. See if you can make it happen. Good luck!
In Part VIII & the final chapter/ of this series we will see how to implement logging using a third party module. We will use "winston" as our logger.We need proper logging in our application. It is a good practice, I am sure you know that. See you then!
Hi, I am Ritesh Patel. I live in a beautiful town surrounded by the mountains. C&O Canal is few miles away. State parks are only a distance away & bike trails galore. It is home sweet home Frederick, MD. A passionate developer. Love to cook. Enjoy playing "Bollywood Tunes" on my harmonica. Apart from that just a normal guy.