I have a MongoDb server hosted on Azure. I'm now building a Node.js API meant to retrieve data from a table on one of the databases (i.e. table: Word; database: MyDatabase). I've built the API following this tutorial, but I'm unable to successfully retrieve any data from it...
I know the server is up and running and also reachable since I can tcp-connect to it through:
psping [Azure's Public IP]:27017
Now, I have an node.js api with the following code:
1) app/server.js
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
mongoose.connect('mongodb://[Azure's public IP]:27017/MyDatabase');
var Word = require('./models/word');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set our port
// ROUTES FOR API
var router = express.Router(); // get an instance of the express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
next();
});
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
router.route('/words')
.get(function(req, res) {
Word.find(function(err, words) {
if (err)
res.send(err);
res.json(words);
});
});
// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
I've also written a model for my only table within the database, which has 3 columns: the auto-generated ObjectId, Spanish, French (meant to have words in both languages to make it work as a translator). The models looks like this: 2) app/models/word.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var WordSchema = new Schema({
spanish: String,
french: String
})
var Word = mongoose.model('Word',WordSchema);
module.exports = Word;
Now, I go to postman and GET on the following: http://localhost:8080/api/words; which returns [].
On MongoDb logs I see the following:
2016-08-05T03:16:26.520+0000 I NETWORK [conn60] end connection [Some IP]:[Some port] (1 connections now open)
2016-08-05T03:31:11.878+0000 I NETWORK [initandlisten] connection accepted from [Some IP]:[Some port] #61 (1 connection now open)
As you mentioned in your comment that the documents were retrieved from db.word.find() I think I found the problem. You need to put documents into collection named words, instead of word.
Mongoose will use the plural version of your model name. See http://mongoosejs.com/docs/models.html for more information.
I think you are missing {} when doing find.
router.route('/words')
.get(function(req, res) {
Word.find({}, //Added here.
function(err, words) {
if (err)
res.send(err);
console.log(words)
res.json(words);
});
});
Hope this will help.
EDIT:-
According the document of doc, the find function accept the first parameter as an object and treat it as conditions, but not a callback function.
Related
I have structured a user collection using mongoose.model().This model exist in seperate file called as model\user.js. The mongodb connection instance (using mongoose) exist in seperate file db\mongoose.js. Both of these files are imported into server.js to work with web application.
var express = require('express');
var bodyParser = require('body-parser');
var {mongoose} = require('./db/mongoose');
var {User} = require('./models/user');
var app = express();
app.use(bodyParser.json());
app.post('/todos', (req, res) => {
var user = new User({
text: req.body.text
});
user.save().then((doc) => {
res.send(doc);
}, (e) => {
res.status(400).send(e);
});
});
app.listen(3000, () => {
console.log('Started on port 3000');
});
module.exports = {app};
The {mongoose} and {User} seems to be a separate entities and model\user.js didn't import ./db/mongoose.js as well . The user model being static content , how does user.save() connects with db and save the document?
First of all let me tell you what is happening in your project.
in Mongoose file:
You have DB connection with Mongoose.
Now Mongoose has your DB connection.
That is the reason it is imported in server.js file.
Secondly, in you model/user.js you have
Declared Schema using Mongoose.
user.save method.
When you use Mongoose here (or any DB related query), it points to your connected DB. Which does not require any explicit connection written in some file.
For more details read Mongoose Docs.
Hope I cleared your thoughts.
I have a express router such as:
var express = require('express')
, router = express.Router()
, bodyParser = require('body-parser')
, mongoclient = require('mongodb').MongoClient
, dbconfig = require('../assets/config.db.json');
router.use( bodyParser.json() );
router.use(bodyParser.urlencoded({
extended: true
}));
router.post('/api/search', (req, res, next) => {
var term = req.body.searchTerm;
mongoclient.connect(dbconfig.url, (err, db) => {
db.accessDatabase(term, (err, result) => {
db.close();
if (err) res.json({result: err});
res.json(result);
});
});
});
module.exports = router;
I have have read that if there is a lot of overhead to make a connection to my db each REST call then I need to make a persistent connection for someone using this REST API. What is the proper way to do this within my router? Right now each time a post request is received it will open a connection, access the db and then close the connection.
EDIT: for clarity I used db.accessDatabase(), but this is not the actual syntax being used within my code.
You open do MongoClient.connect once when your app boots up and reuse the db object. It's not a singleton connection pool each .connect creates a new connection pool.
From node-mongodb-native
Personally, i do it like this
var params = {/*config, etc... required to bootstrap models */}
require('./app/models')(params)
.then(afterModels)
.then(startServer)
function afterModels(theModels) {
params.models = theModels
let providers = require('./app/providers')(params)
params.providers = providers
// boot strap routes
require('./app/routes')(params)
// controllers can use params which has models (db object,e tc.. inside)
}
function startServer() {}
I'm having some trouble creating a RESTful API in Node/Express. In the app I'm building, a user has many messages, and messages belong to users. I need to be able to make an HTTP requests to retrieve all messages by a particular user. Here's the basic structure of the app, starting with the basic server, which delegates routing to a file called 'config/middleware.js'.
//server.js
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
require('./config/middleware.js')(app, express);
var port = process.env.PORT || 8080;
app.use(bodyParser.json());
app.use(express.static(__dirname + '/../client'));
app.listen(port);
This is the middleware file where we send requests to the appropriate router. A request made to 'users/5/messages' would get routed to the messages router, and a request made to 'users/5' would get routed to the users router.
// config/middleware.js
module.exports = function(app, express) {
var usersRouter = express.Router();
var messagesRouter = express.Router();
app.use('/users/:userId/messages', messagesRouter);
app.use('/users', usersRouter);
require('../routers/users')(usersRouter);
require('../routers/messages')(messagesRouter);
};
This is the messages router. If a get request is made to '/users/5/messages', I want the getAllMessages function to be run, which should return all messages by the user with userId 5.
// routers/messages.js
var messagesController = require('../controllers/messages');
module.exports = function(app) {
app.get('/:messageId', messagesController.getMessage);
app.get('/', messagesController.getAllMessages);
};
The problem is that the getAllMessages function doesn't have access to the 'userId' parameter (with value of 5), which is required in order to make an appropriate query to the database. The getAllMessages function in the controller expects the userId to be stored on req.params.userId. Is there any way to get the userId of 5 to be present on the req.params object inside the getAllMessages function?
The req.params are not passed down the route chain. To do so, you could do something like
In server.js, create a key on req. This will pass on your data between routes. Do this before mounting the routes.
app.use(function (req, res, next) {
req._data = {};
next();
});
In config/middleware.js,
module.exports = function(app, express) {
var usersRouter = express.Router();
var messagesRouter = express.Router();
// attach usedId
app.use('/users/:userId/messages', function (req, res, next) {
req._data.userId = req.params.userId;
next();
});
// mount the router
app.use('/users/:userId/messages', messagesRouter);
app.use('/users', usersRouter);
require('../routers/users')(usersRouter);
require('../routers/messages')(messagesRouter);
};
This way, you would have access to req._data.userId in routers/messages.js.
Side note: A better way to structure the routes would be to use something like, (read shameless plug), https://github.com/swarajgiri/express-bootstrap/blob/master/web/routes.js
You can use app.locals or res.locals to pass some datas.
There is a good explanation about locals.
An usage sample:
app.locals.userid = req.params.userId; //binding userid
app.locals.userid // => '5'
OR: put a global variable.
user_id_tmp = req.params.userId;
Now this is become global variable in app. So you can call user_id_tmp variable from anywhere.
I was looking for same.
Here is modules app example on github and auther site
Also we can change or update structure base on our requirements
REST API and Node newbie here. I'm trying to make a REST API in nodejs. Each user would be able to get items associated with their userid and the authentication mechanism is obviously separate from the url. I'm working with something like the following services.
/api/users/userid
/api/users/userid/cars/carid
I expect to have other APIs similar to the 2nd one in the future.
The issue is how to 'bind' the userid and carid or houseid parameters in a clean way. My hope was to be able to have an intermediate step which would capture the 'userid' parameter in the users.js file and then it would delegate the request to the other components. I hoped that this would allow me a more concise authentication checking but there may be more preferable ways. The problem right now is that userid is guaranteed to be unique but carid and houseid are only unique per user so I will need both values to retrieve the data.
My Question is how can I achieve this or is there a better way to organize this to facilitate concise reusable code in terms of authenticating that a user has access to that API. Also if this is very unREST-like, please correct me.
And I have the following code:
app.js
var express = require('express');
var app = express();
app.use('/api', require('./routes/api'));
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('The server is up at ' + host + ':' + port);
});
./routes/api.js
var express = require('express');
var router = express.Router();
/* GET api listing. */
router.get('/', function(req, res, next) {
res.send('Base of our APIs');
});
router.use('/users', require('./users.js'));
router.use('/', function(req, res) {
res.send('Unauthorized api access. Not authorized for ' + req.baseUrl);
})
module.exports = router;
./routes/users.js
var express = require('express');
var router = express.Router();
router.use('/:user_id/cars', function(req, res, next) {
console.log('Userid is:' + req.params.user_id);
// Authenticate a user here before sending to the next page
var cars_api = require('./cars.js');
cars_api(req, res, next);
});
module.exports = router;
./routes/cars.js
var express = require('express');
var router = express.Router();
/* GET cars for user */
router.get('/', function(req, res, next) {
res.send('Retrieving all cars for user ' + req.params.user_id);
});
router.get('/:car_id', function(req, res, next) {
res.send('Retrieving car with car_id ' + req.params.car_id + ' and user id ' + req.params.user_id);
});
module.exports = router;
I've tried several other ways of calling the cars API that all req.params values are cleared in between. I'm using WebStorm to debug.
You would not necessarily need to write the full route like that, something you might want to look into is nested routes, I think that would help.
Rest with Express.js nested router
here you have a great example I started using when I built my first api.
At the suggestion of commenters, I have decided to just write routes directly to the cars api in the form of /users/:user_id/cars/:car_id.
I'm having some troubles trying to stablish a REST API with nodeJS and express. The following code defines two routes, "stores" and "user".
Surprisingly, the route to "/user" is working nice but when a request arrives to "/stores" the request body appears undefined. I've searched for a solution but nothing seems to work for me.
Both controllers have the same structure.
What am I doing wrong?
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override"),
mongoose = require('mongoose');
// Connection to DB
mongoose.connect('mongodb://localhost/appDB', function(err, res) {
if(err) throw err;
console.log('Connected to Database');
});
// Middlewares
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
//Import models and controllers
var userModel=require("./models/user.js")(app,mongoose);
var storeModel=require("./models/store.js")(app,mongoose);
var usersController=require("./controllers/users.js");
var storesController=require("./controllers/stores.js");
//Router options
var router=express.Router();
router.route('/stores')
.get(storesController.getNearestStores);
router.route('/user')
.post(usersController.addUser);
app.use(router);
//Start server
app.listen(3000, function() {
console.log("Node server running on http://localhost:3000");
});
Thank you very much.
P.S.:First time with nodejs and express(and even mongo)
This is because there is no body on a GET request in the http standard. Only POST and PUT.
What you want to do instead is use a query string
get
/stores?location=mystore
this way on your callback you have access to req.query
req.query
{
location: 'mystore'
}
HTTP GET with request body
This gave me the solution, get requests don't accept parameters under HTTP standard.