I am trying to make API for sample Menu Data in which the data must be fetched and shown by entering Restaurant ID. Controller, Model and Router is set but I load it in Postman the data is not showing also if I console.log() the result, its showing an empty array. Please share your ideas. Thanks in advance.
Controller (Menu.js)
const Menu = require('../Models/Menu');
exports.getMenu = (req, res) => {
Menu.find({
restID: req.params.restID
}).then(result => {
res.status(200).json({
menus: result,
message: "Menu Data Success"
});
console.log(result);
}).catch(error => {
res.status(500).json({
message: error
});
})
}
Model (Menu.js)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MenuSchema = new Schema({
item: {
type: String,
required: true
},
cost: {
type: Number,
required: true
},
description: {
type: String
},
restID: {
type: Number,
required: true
}
});
module.exports = mongoose.model('menus', MenuSchema, 'Menu');
Router (router.js)
const express = require('express');
const MenuController = require('../Controllers/Menu');
const router = express.Router();
router.get('/restaurantMenu/:restID',MenuController.getMenu);
module.exports = router;
Currently i am working on Express with Mongoose ODM to build a RESTful API for my mobile app. In my Mongoose Schema i have a title: Index field. I follow Mongoose Unique Index Validation Document to create Unique Document in MongoDB, bellow is my code
Mongoose Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CategorySchema = new Schema({
title: { type: String, required: true, index: true, unique: true },
details: { type: String, required: false },
thumbnail: { type: String, required: false },
created: { type: Date, default: Date.now },
modified: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Category', CategorySchema);
Express Code
var express = require('express');
var routes = express.Router();
var Category = require('./models/category.model');
routes.route('/categories')
.post(function(req, res) {
Category.on('index', function(error) {
if(error) {
res.send(error);
}
Category.create({ title: req.body.title, details: req.body.details,
thumbnail: req.body.thumbnail }, function(error) {
if(error) {
res.send(error);
}
res.json({ message: 'Category was save successfully..!' });
});
});
});
Problem:
Now my problem is that, when i send a POST request to my API http://localhost:3000/api/v1.0/categories. It will not send any response to my client application. This will not show any Warning or Error in server console.
I don't see the point in having
Category.on('index', function(error) {
if(error) {
res.send(error);
}
}
there. Do you want to listen to the index event inside a controller function? Probably not.
You can move
Category.create({ title: req.body.title, details: req.body.details,
thumbnail: req.body.thumbnail }, function(error) {
if(error) {
res.send(error);
}
res.json({ message: 'Category was save successfully..!' });
});
out of it. You should also make sure you return after sending a response, otherwise you might end up sending several responses. Inside if(error) you do a res.send(error) but it will continue to the res.json() later.
So if the rest of your code is correct then this might work:
var express = require('express');
var routes = express.Router();
var Category = require('./models/category.model');
routes.route('/categories').post(function(req, res) {
Category.create({
title: req.body.title,
details: req.body.details,
thumbnail: req.body.thumbnail
}, function(error) {
if(error) {
return res.status(500).json(error);
}
return res.status(201).json({ message: 'Category was save successfully..!' });
});
});
You will get an error message if you break the unique constraint for title. This will happen when you do the create. You have to restart the app before the unique constraint starts working.
I have an overloaded fetch function on an Angular service 'PostSvc'
if a user is provided as an argument the idea is to only return that users posts. Otherwise fetch all posts from the database....
The user is an 'object' passed from the post.ctrl.js with the following keys
{
username: $scope.currentUser,
body: $scope.postBody,
user_id: $scope.currentUser._id
}
this is giving me the _id field mongodb/mongoose generate as expected
console.log($scope.currentUser._id)
Here's the Mongoose Post model:
var db = require('../db')
var Post = db.model('Post', {
username : { type: String, required: true },
body : { type: String, required: true },
user_id: { type: String, required: true },
date : { type: String, required: true, default: Date.now },
})
module.exports = Post
Here's a snippet from the server.js file assigning the router:
app.use("/api/posts", require("./controllers/api/posts"))
Here's the Express './controllers/api/post.js' Router:
var Post = require('../../models/post')
var router = require('express').Router()
var websockets = require('../../websockets')
// this route works just fine
// returns All posts from the db
//
router.get("/", function(req, res, next) {
// find all posts from db
//
Post.find()
.sort("-date")
.exec(function(err, posts) {
if (err) { return next(err) }
res.json(posts)
next()
})
})
the probelem....
router.get("/:user_id", function(req, res, next) {
var query = {}
// these messages aren't being logged to console
// so there's no way the route is being used
console.log("from the get 'api/posts' method" )
console.dir(req.params.user_id)
if (req.params.user_id) {
query = { user_id: req.params.user_id } // sent from posts.svc.js
}
// this query is not executing properly
// I have no access to the `req.params.user_id`
//
Post.find({ user_id: req.params.user_id })
.sort("-date")
.exec(function(err, posts) {
if (err) { return next(err) }
res.json(posts)
next()
})
})
router.post("/", function(req, res, next) {
var post = new Post({ body: req.body.body })
if (!req.auth) { return res.sendStatus(401) }
post.username = req.auth.username
post.user_id = req.body.user_id
post.save(function(err, post) {
if (err) { return next(err) }
websockets.broadcast("new_post", post)
res.status(201).json(post)
})
})
module.exports = router
And last but not least here is the Angular Service that sends the initial 'GET' request to the 'server.js' -> './controllers/api/posts.js' and awaits the response:
angular.module("app").service('PostsSvc', function($http) {
this.fetch = function(user) {
var credentials = {}
if (user) {
credentials = user
// checkpoint
//
console.dir("from the fetch function " + credentials._id)
// only return authencated users posts
return $http.get("/api/posts", {
params: {
user_id: credentials._id // to the posts.js router
}
})
// return all posts otherwise
} else { return $http.get("/api/posts") }
}
this.create = function(post) {
return $http.post("/api/posts", post)
}
})
I have being in this same trouble with the router.get in express. The body is empty. I finally turned to use instead a router.post() which worked perfectly for me, as long as you also call the api with a post request whit angular.
I'm new to node.js and mongoose, and I'd appreciate it if someone could help me with the below error.
I make a put request via the following function (the point of the function is to "upvote" a forum post.
o.upvote = function(post) {
return $http.put('/posts/' + post._id + '/upvote')
.success(function(data){
post.upvotes += 1;
});
};
That in turn goes to my route:
index.js (my route)
router.put('/posts/:post/upvote', function(req, res, next) {
req.post.upvote(function(err, post){
if (err) { return next(err); }
res.json(post);
});
});
And below is my model
Posts.js
var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
title: String,
link: String,
upvotes: {type: Number, default: 0},
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
mongoose.model('Post', PostSchema);
PostSchema.methods.upvote = function(cb) {
this.upvotes += 1;
this.save(cb);
};
In my index.js route, the below error is thrown on the line "req.post.upvote":
TypeError: req.post.upvote is not a function
req.post will not be set automatically. You need another middleware to set it, but most likely you want to get it from the DB with the parameter.
const Post = mongoose.model("Post");
router.put("/posts/:post/upvote", (req, res, next) => {
Post.findById(req.params.post, (err, post) => {
if (err) return next(err);
post.upvote((err, post) => {
if (err) return next(err);
res.json(post);
});
});
});
EDIT: You also need to set the methods before you create the schema in mongoose:
PostSchema.methods.upvote = function(cb) {
this.upvotes += 1;
this.save(cb);
};
mongoose.model('Post', PostSchema);
I'm building a node.js app that is a REST api using express and mongoose for my mongodb. I've got the CRUD endpoints all setup now, but I was just wondering two things.
How do I expand on this way of routes, specifically, how do I share modules between routes. I want each of my routes to go in a new file, but obviously only one database connection as you can see i've included mongoose at the top of people.js.
Do I have to write out the schema of the model 3 times in my people.js? The first schema defines the model, then I list all the vars out in the createPerson and updatePerson functions. This feels like how I made php/mysql CRUD back in the day lol. For the update function, I've tried writing a loop to loop through "p" to auto detect what fields to update, but to no avail. Any tips or suggestions would be great.
Also, I'd love any opinions on the app as a whole, being new to node, it's hard to know that the way you are doing something is the most efficient or "best" practice. Thanks!
app.js
// Node Modules
var express = require('express');
app = express();
app.port = 3000;
// Routes
var people = require('./routes/people');
/*
var locations = require('./routes/locations');
var menus = require('./routes/menus');
var products = require('./routes/products');
*/
// Node Configure
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
// Start the server on port 3000
app.listen(app.port);
/*********
ENDPOINTS
*********/
// People
app.get('/people', people.allPeople); // Return all people
app.post('/people', people.createPerson); // Create A Person
app.get('/people/:id', people.personById); // Return person by id
app.put('/people/:id', people.updatePerson); // Update a person by id
app.delete('/people/:id', people.deletePerson); // Delete a person by id
console.log('Server started on port ' + app.port);
people.js
//Database
var mongoose = require("mongoose");
mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');
// Schema
var Schema = mongoose.Schema;
var Person = new Schema({
first_name: String,
last_name: String,
address: {
unit: Number,
address: String,
zipcode: String,
city: String,
region: String,
country: String
},
image: String,
job_title: String,
created_at: { type: Date, default: Date.now },
active_until: { type: Date, default: null },
hourly_wage: Number,
store_id: Number, // Inheirit store info
employee_number: Number
});
var PersonModel = mongoose.model('Person', Person);
// Return all people
exports.allPeople = function(req, res){
return PersonModel.find(function (err, person) {
if (!err) {
return res.send(person);
} else {
return res.send(err);
}
});
}
// Create A Person
exports.createPerson = function(req, res){
var person = new PersonModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
address: {
unit: req.body.address.unit,
address: req.body.address.address,
zipcode: req.body.address.zipcode,
city: req.body.address.city,
region: req.body.address.region,
country: req.body.address.country
},
image: req.body.image,
job_title: req.body.job_title,
hourly_wage: req.body.hourly_wage,
store_id: req.body.location,
employee_number: req.body.employee_number
});
person.save(function (err) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "Person was not created." });
}
});
return res.send(person);
}
// Return person by id
exports.personById = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
if (!err) {
return res.send(person);
} else {
console.log(err);
return res.send(404, { error: "That person doesn't exist." });
}
});
}
// Delete a person by id
exports.deletePerson = function (req, res){
return PersonModel.findById(req.params.id, function (err, person) {
return person.remove(function (err) {
if (!err) {
return res.send(person.id + " deleted");
} else {
console.log(err);
return res.send(404, { error: "Person was not deleted." });
}
});
});
}
// Update a person by id
exports.updatePerson = function(req, res){
return PersonModel.findById(req.params.id, function(err, p){
if(!p){
return res.send(err)
} else {
p.first_name = req.body.first_name;
p.last_name = req.body.last_name;
p.address.unit = req.body.address.unit;
p.address.address = req.body.address.address;
p.address.zipcode = req.body.address.zipcode;
p.address.city = req.body.address.city;
p.address.region = req.body.address.region;
p.address.country = req.body.address.country;
p.image = req.body.image;
p.job_title = req.body.job_title;
p.hourly_wage = req.body.hourly_wage;
p.store_id = req.body.location;
p.employee_number = req.body.employee_number;
p.save(function(err){
if(!err){
return res.send(p);
} else {
console.log(err);
return res.send(404, { error: "Person was not updated." });
}
});
}
});
}
I have taken another approach here. Not saying it is the best, but let me explain.
Each schema (and model) is in its own file (module)
Each group of routes for a particular REST resource are in their own file (module)
Each route module just requires the Mongoose model it needs (only 1)
The main file (application entry point) just requires all route modules to register them.
The Mongo connection is in the root file and is passed as parameter to whatever needs it.
I have two subfolders under my app root - routes and schemas.
The benefits of this approach are:
You only write the schema once.
You do not pollute your main app file with route registrations for 4-5 routes per REST resource (CRUD)
You only define the DB connection once
Here is how a particular schema file looks:
File: /schemas/theaterSchema.js
module.exports = function(db) {
return db.model('Theater', TheaterSchema());
}
function TheaterSchema () {
var Schema = require('mongoose').Schema;
return new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
address: { type: String, required: true },
latitude: { type: Number, required: false },
longitude: { type: Number, required: false },
phone: { type: String, required: false }
});
}
Here is how a collection of routes for a particular resource looks:
File: /routes/theaters.js
module.exports = function (app, options) {
var mongoose = options.mongoose;
var Schema = options.mongoose.Schema;
var db = options.db;
var TheaterModel = require('../schemas/theaterSchema')(db);
app.get('/api/theaters', function (req, res) {
var qSkip = req.query.skip;
var qTake = req.query.take;
var qSort = req.query.sort;
var qFilter = req.query.filter;
return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
.exec(function (err, theaters) {
// more code
});
});
app.post('/api/theaters', function (req, res) {
var theater;
theater.save(function (err) {
// more code
});
return res.send(theater);
});
app.get('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.put('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
// more code
});
});
app.delete('/api/theaters/:id', function (req, res) {
return TheaterModel.findById(req.params.id, function (err, theater) {
return theater.remove(function (err) {
// more code
});
});
});
};
And here is the root application file, which initialized the connection and registers all routes:
File: app.js
var application_root = __dirname,
express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
http = require('http');
var app = express();
var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');
app.configure(function () {
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(application_root, "public")));
app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.get('/api', function (req, res) {
res.send('API is running');
});
var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
// more code
app.listen(4242);
Hope this was helpful.
I found this StackOverflow post very helpful:
File Structure of Mongoose & NodeJS Project
The trick is to put your schema into models directory. Then, in any route, you can require('../models').whatever.
Also, I generally start the mongoose db connection in app.js, and only start the Express server once the connection is up:
mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
console.log("Error while connecting to MongoDB: " + err);
process.exit();
});
mongoose.connection.on('connected', function(err) {
console.log('mongoose is now connected');
// start app here
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
});
I'd take a look at this project https://github.com/madhums/node-express-mongoose-demo . It is a great example on how to build a nodejs application in a standard way.