How does the framework know which api is been called? - javascript

How does the framework know which api is been called?
app.get('/user/:userId/name/export', function (req, res) {
var userId = req.params.userId;
}
app.get('/user/:userId/name/:name', function (req, res) {
var userId = req.params.userId;
var name = req.params.name
}
I'm working on an api gateway, need some customization of access control. It need to block the api call and check the roles of user through the params in path, like userId and name in db. If matched the config in file, will pass the acl and call the api, otherwise, will return 401. So if the url pattern is similar, I found it's hard to distinguish two api which is exactly been call. Any suggestions? Really appreciate for you help!

Express router calls each callback, which match the URL path.
Route /user/123/name/admin matches only the second path, but route /user/123/name/export matches both of them.
If you end the request on the first callback, then the second will never be called:
app.get('/user/:userId/name/export', function (req, res) {
var userId = req.params.userId;
res.end();
}
app.get('/user/:userId/name/:name', function (req, res) {
var userId = req.params.userId;
var name = req.params.name
}
Callbacks will be called according to adding sequence. So the global paths, like app.get('*', ...) must be added at the very end.

Related

Can I pass the parameters (req, res, next) of a function to another function?

I searched a little bit but I did not find what I am searching for.
I have Node application and two functions:
router.get('/get/user-relevant-data', (req,res,next)=>{
//some code is executed here
return res.status(200).json(userRelevantData)
})
router.get('/get/updated-user', (req,res,next) => {
// I want to call '/get/user-relevant-data' and assign the returned object to another variable
let userRelevantData = // how to call the function here correctly?
})
How would I do such things (if it's feasible) or should such code be avoided? If such code should be avoided, what else could I do except putting the code of the one function into the other.
you can change the way you set up router in that way you can apply as many middlewares as you want like this:
const middleware1 = require("....") //adress to the file your middleware is located
const middleware2 = require("....") //adress to the file your middleware is located
router.get('/directory', middleware1, middleware2 )
and in another file you define middlewares in this way :
exports.middleware1 = (req, res, next) => {
//do some coding
req.something= someDataToPass
next()
//you add the data you want to pass to next middleware to the req obj
// and then access that in the next middleware from the req object then
// call next to run the next middleware
}
then in another file or the same file you type another middleware like this:
exports.middleware2 = (req, res, next) => {
//do some coding
data = req.something
//get data from last middeleware
res.json({})
}
and at the same time you have access to all the req data in both middlewares

How to access application-level middleware from router?

I am trying to access my application-level middleware from router in a project generated with express application generator.
Middleware is used to query database with user ID received from router.
I feel like I'm missing something very simple (or fundamental) but can't get around the problem (this being my first Node.js project). So more than best practice I'm looking for a simple solution
I've tried using different app methods including post.
/app.js
var MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
app.use(MyAppMidW);
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
res.send(req.app.get.MyAppMidW(req.header('auth-header'))); //The problem
}
else {
res.send(req.app.get('defaultData')); //This works
}
});
Error messages include "$middleware is not a function" and "$middleware is not defined".
Solution
/app.js
app.MyAppMidW = function (req) {
queryDB(req);
}
/routes/index.js
router.get("/dbquery", (req, res) => {
if (req.header('auth-header')) {
req.app.MyAppMidW(req.header('auth-header'))); //Makes a database query
res.send(req.app.get('defaultData')); //Fetches database query result
}
else {
res.send(req.app.get('defaultData'));
}
});
If you do it like this
app.use(MyAppMidW);
Every request will query your db, and thats not what you want. I guess you use the MVC design pattern.
In your route folder you have something like this:
import appController from "../controllers/app.js"
router.get("/dbquery", appController.MyAppQuery)
And in your controllers folder you have your logic that querys the db
exports.MyAppQuery = (req, res){
//If u use mongodb for example
YourModel.find().then(data => {
res.json(data)
})
}
You need to call app.set("MyAppMidW", MyAppMidW) and then you can use get. Or do this inside the app.js file
app.MyAppMidW = function (req, res, next) {
res.send(queryDB(req));
next()
}
Then call it by req.app.get('MyAppMidW')(req.header('auth-header')) or req.app.MyAppMidW(req.header('auth-header')) inside the routes file.
But middleware is called automatically when you say app.use(MyAppMidW) the function is called by default on each request. So no need to call it explicitly inside the router function.

Pass data between express router and middleware

I'm trying to write express middleware to check the validity of a JWT in the Authorization header. This seems quite easy but I don't want it to run on all routes (e.g. not on login/signup routers).
So, I'd like to specify in the router declaration that a route should require a valid token. E.g. something like this
const controllers = require('../controllers');
module.exports = (app) => {
app.post('/auth/signup', controllers.auth.signup.post);
app.post('/auth/login', controllers.auth.login.post);
app.get('/teams', controllers.teams.get, {requiresToken:true});
};
Except, .post and .get don't take a third parameter and the controller only takes (req,res,next) parameters so I can't really see a way of passing startic data for each route. I'm sure I'm missing something simple
This is how i created a middleware to pass the data into
module.exports = function(options) {
return function (req, res, next) {
//write your code here
// here you can access options variable
console.log(options.data)
next();
}
}
How you call that middleware is like this
app.use(middleware({'data' : 'Test'}));
To use on route basis
app.post('/userRegistration', middleware({'data' : 'Test'}), (req, res) => {});
You can exclude the auth subroute from this middleware using negative lookup regexp:
const controllers = require('../controllers');
module.exports = (app) => {
app.use(/\/((?!auth).)*/, yourJwtTokenValidatorMethod); // replace with your jwt token validator middleware
app.post('/auth/signup', controllers.auth.signup.post);
app.post('/auth/login', controllers.auth.login.post);
app.get('/teams', controllers.teams.get, {requiresToken:true});
};

ExpressJS > router middleware > passing variable req.foo via redirect not working

Let's say I have this:
a) 2 routes with 1 middleware function each and a callback function:
router.post('/foo', fooCtrl, function(req, res)
{
res.redirect('/bar');
});
router.get('/bar', barCtrl, function(req, res)
{
res.end('finished');
});
b) 2 middleware function expressions
fooCtrl = function(req, res, next)
{
req.foo = 'foo';
next();
};
barCtrl = function(req, res, next)
{
console.log(req.foo); // output is 'undefined'
next();
};
As you can see, in the fooCtrl I'm setting a variable req.foo - and in this scope it is set than... but I'm not able to call this variable in the barCtrl-scope.
Isn't the req object passed by reference?
Any suggestions or best practices?
The purpose of this is to pass a token after login from the login-controller to an admin-controller .. something like that.
That is the expected behaviour. req object is created anew for each new request and your redirection i.e. res.redirect('/bar') results in a new request.
Solution:
You may use some package e.g.connect-flash which stores variables in a temporary session object, which can be used only once. You need to set required values in your flash objects before redirecting. Then after redirection, you will be able to get the saved values from the flash object itself.

How to build a typical REST type system with Node.js

I am really confused on how to build a typical REST type web app with Node.js (even though I am using Sockets).
In a typical WAMP stack you have a public javascript file and server-side PHP files. The user might be able to execute a JS function like
function updateDetails(){
$.post('details.php', formData, function(data){
console.log(data);
},'json');
}
And the server-side PHP file is something like
var stmt = "UPDATE table SET user = :user";
var params = (':user', $user);
stmt->execute();
Now I do know about node-mysql, but I don't see how it is implemented in the same way. How can I maintain a list of statements on the server side and allow the user to simply execute these statements on the client side.
I have node_modules/mysql installed.
In my server (app.js)
var mysql = require('mysql');
But unless I add all my statements there, I don't seem to be able to access them from a public JS file.
There are libraries out there that wrap database tables as resources and expose them as REST services (GET, POST, PUT, DELETE).
For example, sails.js uses Waterline for this purpose. You should look into other similar frameworks if you do not want to write the routes from scratch.
If you're just using express (4.x), then you can declare routes like the following:
// In users.js
var express = require('express');
var users = new express.Router();
users.get('/', function (req, res, next) {
// access mysql, grab all users, then...
res.json(results);
})
users.get('/:id', function (req, res, next) {
var userid = req.params.id;
// access mysql, grab user by id, then...
res.json(result);
})
users.put('/', function (req, res, next) {
var newUser = req.body;
// you can also use POST instead of PUT, and alter where the information for the new user should come from.
// insert a new row with the data found in newUser then...
res.json(createdUser);
});
users.delete('/:id', function (req, res, next) {
var userid = req.params.id;
// delete the user by id then...
res.json(deletedUser);
});
If you're really adventurous, or is a stickler for having http methods do exactly what they're supposed to, you can include a PATCH route for updating a user.
You have the option of either including mysql directly in the route, or declaring another module, then referencing that in the route. I'll finish one of the methods completely.
// more complete version of /users/:id
var mysql = require('mysql');
var connectionString = 'fill me in';
var pool = mysql.createPool(connectionString);
users.get('/:id', function (req, res, next) {
var userid = req.params.id;
var statement = "SELECT * FROM 'users' WHERE id = ?";
pool.query(statement, [userid], function (err, rows) {
if (err) { res.status(500).json(err); } // if you want to expose why you can't get the user by id.
else if (rows.length == 0) { res.status(404); } // could not find user with the given id.
else { res.json(rows[0]); } // return the found user.
});
})

Categories

Resources