Express.js routing between files - node.js

i have 3 files: server.js, bookhandler.js, books.js
i assume that there will be requests like: /book/name, /book/type, /book etc.
according to the first field in the url, which is book(it can also be video and magazine),i want my server.js to direct me to the bookhandler.js file with the post parameters. i only want a function here which i can validate the parameters. and if parameters are valid, i want to pass the parameters to my books.js file which i can make my post request with those valid parameters.if the first field of url is video, it should direct me to videohandler etc.
server.js
app.use('/book', require('./bookhandler').middleware);
this is what i did so far, and it directs me to the bookhandler file, but i dont know how to get parameters and validate inside a function
EDİT:
bookhandler.js
var express = require('express');
var app = express();
module.exports.middleware = function (req, res) {
var id = req.body.id;
if(id.length==5) {
app.use('/id', require('../book').middleware));
}
};
book.js
app.post('/id' , function (req, res) {
});
module.exports = app;

You don't direct execution to a file, but to a function. Files are just a way of organizing functions or any type of code.
Based on this example you gave, I assume that bookhandler.js exports a function named middleware in its module.exports object. That function, when called, will be passed a reference to the request and response objects. The request object has the parameters in it.
For example:
bookhandler.js:
module.exports.middleware = function (req, res) {
var bookId = req.params.bookId;
// do something with bookId
};
[Edit based on latest update of question]
You are over-riding module.exports. After setting module.exports.middleware to a valid function, you replace module.exports in its entirety with a reference to app.
Remove this line and your problem should be solved.
module.exports = app;

Related

How to customise get method with different queries in Express.js with Node.js?

I'm currently building a REST API using Node.js with Express.js and I'm quite new to this technology. The following code shows the get method to a list of councils stored in MongoDB.
const { Council } = require('../mongoose-models/council');
const express = require('express');
const router = express.Router();
router.get('/', async (req, res) => {
const query = req.query;
const councilsList = await Council.find(query);
if (!councilsList) return res.status(404).send('No councils found.');
res.send(councilsList);
});
module.exports = router;
From my previous experience when developing REST API using java, I can customise different queries by implementing different methods with their own paths. For example:
#Path("findByCouncilName/{councilName}")
#Path("findCouncilsNotInMyArea/{longitude}/{latitude}")
And within each method, I can then write different logics. However, in Express.js, it seems that I have to implement all these different logics into one block. It seems not flexible and how can actually implement it? Furthermore, does the query must be same as the key name in MongoDB? What if I want to filter the results based on a specified index element in a nested array in a document?
For your routes:
#Path("findByCouncilName/{councilName}")
#Path("findCouncilsNotInMyArea/{longitude}/{latitude}")
If you are to implement them in express, you can split them into different blocks actually.
Instead of listening to '/' and try to handle everything inside, you can try this.
const express = require('express');
const router = express.Router();
router.get('/findByCouncilName/:councilName', async (req, res) => {
const councilName = req.params.councilName;
// Your logic goes here
res.send();
});
router.get('/findCouncilsNotInMyArea/:longitude/:latitude', async (req, res) => {
const longitude = req.params.longitude;
const latitude = req.params.latitude;
// Your logic goes here
res.send();
});
module.exports = router;
You can use it like lets say:
router.get('/:councilName', async (req, res) => {
Then use the parameter in the route with :
req.params.councilName
Express doc is your friend
https://expressjs.com/en/guide/routing.html
Here is everything you should know about express routing.
You can specify individual logic for every pat-method pair, and again, use general as needed.
You need to be aware of path order in which Express resolves them, eg. first path to match will will be executed.

Nodejs, Express, routes

I have build an api using express. In my routes file I have:
app.route('/getBalances')
.post(api.getBalances);
api.getBalances, depending on a parameter send through post called "vehicle" gets first which is the correct controller to load and to invoke its getBalances method, in example:
var controller = commonModel.getController(query.vehicle.toLowerCase());
controller.getBalances();
getBalances is not the only entry point I have, so I was wondering if it was possible to call a "global" method which is call for every entry point, in that way I wouldn't need to identify the correct controller on each method but on the global method.
Thanks in advance for your help.
Use a preliminary middleware which will run before adding any api route. Example:
// This middleware has to be added first.
app.use(function(req, res, next) {
var query = req.query; // or `req.body`, whatever you like
if (query && query.vehicle) {
req.controller = commonModel.getController(query.vehicle.toLowerCase());
}
next(); // delegate request to the next routes
});
// Now add specific api middlewares.
app.route('/getBalances')
.post(function(req, res) {
var controller = req.controller; // we've populated this earlier
res.send(controller.getBalances());
});
app.route('/anotherMethod')
.post(function(req, res) {
var controller = req.controller;
// etc.
});

How to chain middlewares using routers

I'm using express 4.0 and I'm having trouble to chain middlewares. I have 2 routers : a job router and a recruiter router.
Everything works fine at the moment ( I can use CRUDs on both of these routers) but I'd like the POST method for a job to call a method withing the recruiter router and I don't know to achieve this.
router/recruiter.js :
var express = require('express');
var router = express.Router();
/* GET recruiters listing. */
router.get('/', function(req, res, next) {
var recruiters = [];
//get recruiters
res.json(recruiters);
});
function(err, req, res, next) {
console.info("pseudo code for a function I'd like to call in the job.js file");
});
module.exports = router;
router/job.js :
var express = require('express');
var uuid = require('uuid4');
var router = express.Router();
var jobs = [];
/* GET job listing. */
router.get('/', function(req, res, next) {
jobs = [];
//get jobs
res.json(jobs);
});
/* add jobs . */
router.post('/', function(req, res, next) {
console.info('add job', req.body);
var body = req.body;
//I omit the parts where I check the req and save the object
//At the moment I do this but I'd like to call a method within the recruiter router before sending the json back to the client.
res.json({'jobs': []});
});
module.exports = router;
and here are the relevant parts in the app.js :
var job = require('./routes/job');
var recruiter = require('./routes/recruiter');
app.use('/job', job);
app.use('/recruiter', recruiter);
Turning my comment into an answer...
Express does not offer any special way to share code among multiple routes. If you want the code always executed before your route handler, you can, of course, use a common middleware function.
But, if your code sharing case is that you just want two or more routes to be able to execute some common code from within their route implementations, then this is really just a plain Javascript issue. You put the common code into a shared function and you call that function from two or more routes. In other words, you just share code among routes that same way you share code among any other Javascript functions. Express doesn't require anything special in this regard. Do it that way you always do it in Javascript.
It is fairly common that people coding in Express get caught up in the way you structure your code for Express and somehow forget that you can still use regular shared, common functions to share code (I've seen many people caught by this) - expecting their to be an "Express" way to share code. There isn't. Just do the normal Javascript method of sharing common code by creating a function with the common code in it and calling it from more than one place.

Express Routes in Parse Cloud Code Module

I am using parse.com cloud code with express to setup my routes. I have done this in the past with node, and I have my routes in separate files. So, in node I do
app.js
express = require("express");
app = exports.app = express();
require("./routes/js/account");
account.js
app = module.parent.exports.app;
app.get("/api/account/twitter", passport.authenticate("twitter"));
All the examples on parses site https://parse.com/docs/cloud_code_guide#webapp show this being done as follows.
app.js
var express = require('express');
var app = express();
app.get('/hello', function(req, res) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
});
So, I would like to change the bottom to include a routes folder with separate routes files, but am not sure how to do this in parse.
I know this post is a little old, but I just wanted to post a solution for anyone still looking to get this to work.
What you need to do, is create your route file, I keep them in 'routes' forlder, for example <my_app_dir>/cloud/routes/user.js
Inside user.js you will have something that looks like this:
module.exports = function(app) {
app.get("/users/login", function(req, res) {
.. do your custom logic here ..
});
app.get("/users/logout", function(req, res) {
.. do your custom logic here ..
});
}
Then, in app.js you just include your file, but remember that you need to append cloud to the path, and pass the reference to your app instance:
require('cloud/routes/user')(app);
Also, remember that express evaluates routes in order, so you should take that into consideration when importing several route files.
I'm using a different method, have the routes in app.js, but you can probably include them in file if you prefer. Take a look at the example app,
anyblog on github
The way it works:
Set up a controller:
// Controller code in separate files.
var postsController = require('cloud/controllers/posts.js');
Add the controller route
// Show all posts on homepage
app.get('/', postsController.index);
// RESTful routes for the blog post object.
app.get('/posts', postsController.index);
app.get('/posts/new', postsController.new);
And then in posts.js, you can use exports, ex.
var Post = Parse.Object.extend('Post');
// Display all posts.
exports.index = function(req, res) {
var query = new Parse.Query(Post);
query.descending('createdAt');
query.find().then(function(results) {
res.render('posts/index', {
posts: results
});
},
function() {
res.send(500, 'Failed loading posts');
});
};
// Display a form for creating a new post.
exports.new = function(req, res) {
res.render('posts/new', {});
};
Pass the app reference to the post controller, and add the routes from there

How to put middleware in it's own file in Node.js / Express.js

I am new to the whole Node.js thing, so I am still trying to get the hang of how things "connect".
I am trying to use the express-form validation. As per the docs you can do
app.post( '/user', // Route
form( // Form filter and validation middleware
filter("username").trim()
),
// Express request-handler gets filtered and validated data
function(req, res){
if (!req.form.isValid) {
// Handle errors
console.log(req.form.errors);
} else {
// Or, use filtered form data from the form object:
console.log("Username:", req.form.username);
}
}
);
In App.js. However if I put something like app.get('/user', user.index); I can put the controller code in a separate file. I would like to do the same with the validation middleware (or put the validation code in the controller) to make the App.js file easier to overview once I start adding more pages.
Is there a way to accomplish this?
Basically I would like to put something like app.get('/user', validation.user, user.index);
This is how you define your routes:
routes.js:
module.exports = function(app){
app.get("route1", function(req,res){...})
app.get("route2", function(req,res){...})
}
This is how you define your middlewares:
middlewares.js:
module.exports = {
formHandler: function(req, res, next){...}
}
app.js:
// Add your middlewares:
middlewares = require("middlewares");
app.use(middlewares.formHandler);
app.use(middlewares...);
// Initialize your routes:
require("routes")(app)
Another way would be to use your middleware per route:
routes.js:
middlewares = require("middlewares")
module.exports = function(app){
app.get("route1", middlewares.formHandler, function(req,res){...})
app.get("route2", function(req,res){...})
}
I hope I answer your questions.
You can put middleware functions into a separate module in the exact same way as you do for controller functions. It's just an exported function with the appropriate set of parameters.
So if you had a validation.js file, you could add your user validation method as:
exports.user = function (req, res, next) {
... // validate req and call next when done
};

Resources