Accessing request middleware from inside models - node.js

When we setup a Node Express application, by default the main app.js file is created and two routes (index.js and users.js). The request middleware can be directly accessed from inside the routes folder.
//routes/index.js
const user = require('../models/users.js');
const createUser = user.createUser;
router.post('/signup', async (req, res, next) => {
await craeteUser(req);
...
//I can get req.body.anything
})
Is there any way to access the reuest body inside models folder. (say) I have created a users model that has a function like this...
//models/users.js
async function createUser(req)
{
....
//I cannot get req.body.anything
}
module.exports = {createUser}

Related

How do I get the full route path including the parameters from express or extend the request object to do so?

I have the following route in my express (version 4.17.1) API in a postTimecardCompany.js file:
const mongoose = require('mongoose');
const Timecard = require('./../models/timecard');
function postTimecardCompany(server) {
server.post('/api/v1/timecard/:userId', (req, res) => {
// Insert timecard data into the database
Timecard.create(data, (error, result) => {
// Check for errors
if (error) {
res.status(500).end();
return;
}
// Respond
res.status(200).send({timecardId: result._id});
});
});
}
module.exports = postTimecardCompany;
The route (among other routes) is loaded via the following mechanism by server.js file:
[
'postTimecardCompany',
'anotherRoute',
'someOtherRoute',
'andSoOn...'
].map((route) => {
require('./core/routes/' + route + '.js').call(null, server)
});
I have a middleware (in server.js file) where I check which route is being called.
server.use((req, res, next) => {
// If route is "/api/v1/timecard/:userId" do something
});
I have found various solutions which do nearly what I am looking for, but not exactly.
For example, if I post to the route with a data parameter userId value of "123f9b" then req.originalUrl gives an output of "/api/v1/timecard/123f9b."
What i'm looking to get is the original route path with the parameters in it so for a request of "/api/v1/timecard/123f9b" it would be: "/api/v1/timecard/:userId."
How do I get this functionality in express or extend express to get the original route path with parameters in the request object?
if you want to use from your approach, it's is impossible, after that your approach is not standard in express check the documentation, if you want get routes in a middleware you should try like this:
server.js
const express = require('express')
const server = express()
const postTimecardCompany = require('./routes/postTimecardCompany.js')// don't use map()
server.use("/",postTimecardCompany)//use the routes
server.listen(6565,()=>console.log(`Listening to PORT 6565`))
routes of postTimecardCompany.js
use Router of express and export router, and you can use middleware before each route you want, there are many ways to use middleware in routes, check the documentation
const express = require("express");
const router = express.Router();
const middleware = require('../middleware');//require middlewares
router.post("/api/v1/timecard/:userId", middleware,(req, res) => {
// Insert timecard data into the database
console.log(req.route.path);
});
module.exports = router;
middleware.js
module.exports = ((req, res, next) => {
console.log(req.route.path);
next()
});

Why is module.exports=router is needed?

In my node.js server conf file, I set app.use('/user', user.js), which maps /user route to a user.js file.
Then I create subrouting in my user.js file to handle my get or post requests.
My question is: what's the responsibility of module.exports=router at the end of this file?
If I remove it, routing stops working, so I don't understand if it is here to tell my server conf file that there are sub paths in user.js?
var express = require('express');
var user = require('../../models/user');
var db = require('../../models/index');
var router = express.Router();
router.get('/addUser',function (req, res, next) {
db.user.create(req.body)
.then(user => res.json({
data: user,
}))
.catch(error => res.json({
error: true,
data: [],
error: error
}));
});
module.exports = router;
When you do
var user = require('../../models/user');
the user object would get whatever is being exported from the module in user.js. So in user.js, the module.exports=router is mapping a router and all logic that's required to map /user (along with the right callbacks etc...)
If you remove it, your require statement can't acquire an exported object from that module, which is why it would fail. Your user object will be nullified effectively.
Check out here for more info: https://www.tutorialsteacher.com/nodejs/nodejs-module-exports
A router cannot listen(PORT) for requests on its own. The router is useful when you have lots of routes. It's useful for separating your app into multiple modules.
const app = express()
app.listen(port)
app is listening for the requests(not the Router) while your user.js is just a separate js file with some codes.
In module.export ,module is a variable that represents the current module and export is an object. Anything you assign to the module.exports will be expose as a module.
copied: Module in Node.js is a simple or complex functionality organized in single or multiple JavaScript files which can be reused throughout the Node.js application.
Once you do module.export = Router Now you have a newly created module. In nodeJs, you need to require a module before use it. const user = require('./user.js') will do that process. Once you require the node module into your app, you need to tell it to execute by app.use('/' , user)
Or you can do something like below too
in your user.js file,
var user = require('../../models/user');
var db = require('../../models/index');
module.export = (app) =>{
app.get('/addUser',function (req, res, next) {
db.user.create(req.body)
.then(user => res.json({
data: user,
}))
.catch(error => res.json({
error: true,
data: [],
error: error
}));
});
}
in your main index.js,
const app = express()
require('./user.js')(app)

Communication between middleware and route in keystonejs

I am using keystone and I have productDetail route in which I can add variables in res.locals to be used in templates. Is there a way I can use res.locals (of route file) in middleware.js file? As right now middleware is executing before route, I want route file to be executed first.
This is where middleware is executing in index.js file
keystone.pre('routes', middleware.initLocals);
And after that we have
exports = module.exports = function(app) {
// Views
app.get('/', routes.views.index);
app.get('/product-detail/:product', routes.views.productDetails);
}
I'm not sure if I got your question but this might help. You can run as many custom middleware you want after the middleware.initLocals (which apparently runs first). In your routes/middleware.js file, you can have, for example, two middleware:
exports.middleware0 = function (req, res, next) {
// Do some stuff
next();
};
exports.middleware1 = function (req, res, next) {
// Do some other stuff
next();
};
Then, inside your routes/index.js you can chain middleware together:
//...
var middleware = require('./middleware');
//...
exports = module.exports = function (app) {
// Use the middleware0 and middleware1:
app.get('/product-detail/:product', [middleware.middleware0, middleware.middleware1], routes.views.productDetails);
};

How to split a routes.js that grows too large to be easily maintained?

I'm using node and express to create a rest api. I followed a tutorial where all the routes and its logic are saved in a routes.js file like this:
SERVER JS:
var express = require('express');
var app = express();
(...)
require('./app/routes.js')(app, port, express);
ROUTES.JS
module.exports = function(app, port, express) {
var apiRoutes = express.Router();
(...)
//Sample route
apiRoutes.get('/userfiles', function(req, res) {
UserFile.find({ owner: req.decoded.user.email }, function(err, filesList) {
if (err)
return done(err);
res.json({ success: true, files: filesList });
});
});
My problem is twofold:
1 - Routes can easily contain code thats 150 lines long, some of them far longer. It doesn't feel clean to have route declarations and the logic grouped together. Is it a good practice to do something like this instead?
apiRoutes.post('/randomRoute', function(req, res) {
return res.json(functionThatContainsTheActualCode(req));
});
(and then have an functionThatContainsTheActualCode function with all the logic in a different file).
2 - I have middleware that applies to some functions (for example, some routes are only accessible for logged in users and those routes go through an authentication middleware). Currently way I do it is declaring public routes before the middleware declaration and private routes after, which feels incredibly hacky. How can I separate public and private routes (and the middleware itself) in different files?
Problem 1:
We need to go deeper.
Change the route file to just require the actual router logic.
routes.js
// where app = express();
module.exports = (app) => {
// index.js happens to be a file exporting the router.
app.use('/', require('./index'));
// this is basically the idea. Create a separate file for the actual logic.
app.use('/route', require('.path/to/file'));
};
and in file.js
const express = require('express'),
router = express.Router();
router.verb('/path/', (req, res, next) => {
// do whatever
});
// this is required
module.exports = router;
Problem 2:
Middleware is basically a function taking in request, response, next as 3 params, doing something with the request and either sending out a response or moving on to the next middleware. That's why you need to call next if you want to move to next middleware in the chain.
Now all you need is a file that exports a function which takes request, response, next as params.
// lets call this auth.js
module.exports = function(req, res, next) {
// do logic
if () {
return res.send(); // or res.somethingThatSendsOutAHttpResponse()
}
// next middelware
next();
};
Since express routes are also middlewares, (mind blown), you can mount them top down.
To authenticate a route, just put the auth.js middleware on top of that route.
router.get('/', require('./auth'));
router.get('/', require('./log'));
router.get('/', (req, res, next) => {
// yolo
});
Now since this is web dev, you still got problems.
Now all your boring database queries are scattered everywhere.
Fear not, you can solve it, by, guess, creating another file.
apiRoutes.get('/userfiles', function(req, res) {
const userFile = require('/path/to/model/with/userfile/methods/exported/out');
// do something with userFile's methods
});

Dynamically created proxy URL using Node/Express

I want to use express to create unique proxy instances using URLs that I am storing in a database. I found an npm module that may help with this called http-express-proxy but open to other solutions that uses express.
And I had a route like this (using http-express-proxy):
user.URL = 'https://www.google.com'
app.post('/', proxy(user.URL))
// and after this, user.URL is updated to a different value. I want the proxy's address to change too.
I did find a solution that dynamically creates a regular express route during runtime, but I cannot get it to work using the proxy() method from http-express-proxy:
https://alexanderzeitler.com/articles/expressjs-dynamic-runtime-routing/
According to that approach, I can require a 2nd file inside the POST route that looks like this: (and includes a call to the database using sequelize)
const express = require('express')
const proxy = require('express-http-proxy')
const User = require('../db/models/user')
const app = express()
module.exports= {
init : init
}
function init(app) {
User.findOne({where: {id: 1}})
.then(user => app.post('/', proxy(user.URL)))
}
And in my main app.js file, I am then doing this:
// ...
app.post('/', function(req, res, next) {
var dynamic = require('./dynamic')
dynamic.init(app)
})
// ...
But I am getting a 503 response when I post using this approach using http-express-proxy, which was not used in his example.
I got it to work like this. I modified the express-http-proxy module and at the top of the SendProxyRequest() method I included this:
if (req.URL) host = req.URL
And then in my app.js file I added a middleware method to set req.URL after a call to the database:
function getProxyURL (req, res, next) {
User.findOne({where: {id: 1}})
.then(user => {
if(user.URL) req.URL = user.URL
next()
})
}
app.post('/', getProxyURL, proxy('www.default.com'))

Resources