ExpressJS + JWT. What's the proper way to get auth data? - javascript

Let's jump to an example. I'll skip some parts like imports, exports.
I have a controller called controllers/book.js with one route:
router.get('/my-books', function(req, res) {
if(Auth.authenticated(req,res)) {
Book.getMyBooks(function(rows) {
response.operationSucceed(req, res, rows);
});
}
});
Then, in a model called models/book.js I have that function:
function getMyBooks(successCallback) {
db.query('SELECT * FROM book b WHERE b.id_user=?', [Auth.getLoggedUID()], function(rows) {
successCallback(rows);
});
}
My question is about Auth.getLoggedUID function.
Assuming that I have a JWT authentication and assuming that I have an UID in payload (is that even acceptable?), what's the best option to retrieve it? Is there any, EXCEPT passing the req every time to every function where I need auth data?
I may have a function execution inside a function, do I need to pass the req through both of them to get the user ID? Like this?:
function getBooks(req) {
getMyBooks(req);
getCriminalBooks(req);
getEvenOtherBooksByAuthor(req, authorId);
}
Honestly I wouldn't like that.
Maybe my whole concept is wrong and I should be doing things differently?
Can someone point me the right direction in scenarios like this?

You can pass UID in header and retrieve it inside your controller as:
var uid =req.header('UID');
Then pass this UID where ever you want there is no need to carryforward whole req object everywhere.

You can use a middleware function. Let's say that every request that hits your endpoints, will have a token which you should check and possibly decode it. After that, you can set the decoded content to the req object. So something like this:
app.use(function(req, res, next) {
// get the token from the request headers most likely.
// verify and decode the token
// set the decoded content to the request
var payload = ..
req.payload = payload;
});
After this you can access the payload in every single endpoint you have. So for example in some controller you can do:
app.get('/hey', function(req, res) {
var payload = req.payload;
});

Related

Express js repeat route journey with context

I've been sitting with this for few days already and I'm brain dead from this and can't figure the best way to approach this.
What I would like to achieve is to be able to repeat the route journey with new context data on the start. So for rxample:
app.get('/test', testGet);
app.post('/test', testPost);
having those two routes I would like:
GO through testGet handler (fetch necessary data and present ui for Form)
Gather Form data and submit it for the testPost handler
Process data from form on testPost and generate appropirate new payload
Redirect again to the testGet handler with new payload data from testPost if journey not successful
How I would pass that new data to the testGet on redirection? Can't figure the best way.
Redirect doesn't accept any payload. Redirecting with query params is kinda way to go but it appends the url string with query string to the user which I would like not to be present to the user. And that data would not be a simple string but an object containing few arrays and properties
Look at this
const handleRequest = (req, res, next) => {
const view = 'myView.jsx';
let myData = {};
...do the common job
if (req.method === 'GET') {
return res.render(view, data)
}
/* here you are in the post method */
data = /* modify your data with the req.body */
return res.render(view, data)
};
app.get('/test', handleRequest);
app.post('/test', handleRequest);

how to allow pass through in express handlers?

I have anPOST api endpoint lets say /users to fetch the list of users.
It is POST because body of the request is very huge and might not fit in url for GET request.
suppose the body of user POST have a key called age , which should give me user of certain age ie kind of filtering
now in express i have route like
app.post('/users', function(r,res){
// function body
})
and i cant actually put any code inside that function body
so i was able to intercept the request by using one more handler for /users and putting it before the original handler but obviously it intercepts all /users requests and breaks earlier functionality
how can i intercept only the request with particular age and then pass through other requests to the original handler, so that original functionality keeps working?
I want to know how can i do this using route handlers and not middlewares ?
i cant mess with the url or request body also
First off, this sounds like a really bad design so really the better way to fix things is to just fix the URL design so you don't have this conflict between code you can and can't modify. I say this because it sounds like you're trying to "hack" into something rather than make a proper design.
If your code is using the regular body-parser middleware, then the body of the post will already be parsed and in req.body. So, you can look for the desired parameter in req.body.age and check its value.
If it meets your criteria, then you can process the request and you're done. If it doesn't meet your request, then you call next() to continue processing to other request handlers.
// make sure this is defined BEFORE other /users request handlers
app.post('/users', function(req, res, next) {
// test some condition here
if (+req.body.age > 30) {
// process the request and send a response
res.send("You're too old");
} else {
// continue processing to other request handlers
next();
}
})
The way I deal with this is if I have a route that works, and I need something else, I add another route that is similar. This way you leave the original alone - which provides a working service. This is what I think you re describing.
You can call routes anything you like. If you want a list of users you can pass a variable like this:
$.get('/contactCard/'+qry);
app.get('/contactCard/:sort', function(req, res) {
var cId = req.params.sort;
console.log('cId: ' + cId);
then you set up your search query and go get the data a bit like this:
let params = {
TableName: ddbTable,
ProjectionExpression : "cEmail,Forename,Surname",
KeyConditionExpression: "ID = :e ",
ExpressionAttributeValues: {
":e" : cId
}
};
console.log("params", JSON.stringify(params, null, 2));
docClient.query(params, function(err, data) {
then you check for error or success:
if (err) {
console.log("Error:", JSON.stringify(err, null, 2));
} else {
console.log("Success", JSON.stringify(data, null, 2));
let contacts = data;
then here you render to the page you want and pass the data as you wish.
res.render('members/contactcard', {
contacts:contacts,
static_path: '/static'
});
}
});

Dynamic routing in Node.js

I want to create dynamic stubs as webservices. My idea is to load at every request a definition file and return data for corresponding URL.
The definition file could look like this:
/api/users {users:["john", "jack", "jake"]}
/api/users/1 {user:"john"}
/api/some-data/1 {data:"some data"}
In an application I created on behalf of a tutorial I find:
router.post('/some-irl', function (req, res) {
//some code
return {some JSON}
});
But this definition looks static to me, which should be there before I start Node.js Is it possible to define /some-irl at the time then request occures?
EDIT
Actually, I was intending to do somehting like this: https://github.com/typicode/json-server but it is already there!
You can attach a use middleware, which can check the path and decide whether to handle it or pass it on:
router.use(function(req, res, next) {
// req.path
// decide what to do
// respond or next()
});
you can define variables in the routes, use : before the variable name to define it, and then you'll get the value in req.params:
route.get('/api/users/:user/', function (req, res) {
var username = req.params.user;
});

Mongoose pass req object to middleware

I am writing a middleware for mongoose that gets executed for every find object using pre query hook.
postSchema.pre('query', function(query, next) {
// I want to access the req.user object here
query.populate('Category');
next();
});
I want to access req.user object inside the pre for every request made to the api server. How can i pass the object to the middleware?
Is it even possible?
https://github.com/Automattic/mongoose/issues/1931
I found the above but it doesnt talk about passing req object.
====================
Edit after some confusion about the question.
What i am trying to accomplish is to get the req.user role and the model name pass it to another function to get the query condition for find. So depending on the user role and the type of model accessed the query condition will change.
Wrap the middleware in another middleware that has access to req.
Something like, assuming express
router.verb('/some-route', function (req, res, next) {
postSchema.pre('query', function(query, next) {
console.log(req);
query.populate('Category');
next();
});
});
Edit
- Attach this only to the route that you want the prehook for.
Disclaimer - Not tested.
I know i'm joining this party late but you can use a service to pass the data you want between the request object and the mongoose prehook method. In your service create private variables that hold the data that you want to pass. Set those variables in your custom middleware and call the service get method to get the values in the mongoose prehook method.
Use
query.op to get the type of query
query.options to get other options like {runValidators: true}
query._condition to get the conditions of the query
query._update to get the incoming body
query._fields to get the selected fields,
You can also log the query to the terminal to see various options
Yes, it is possible.
restify.serve(router, model, {
preCreate: function (req, res, next) {
req.body.createdBy = req.user._id
next()
}
})
Follow this doc

Easy way to handle post data in meteor.js?

I need to handle some POST data in my meteor.js app, is there an easy way to do this?
Very basic, if it was a PHP app I would just want the $_POST variable.
Meteor router
https://github.com/tmeasday/meteor-router#server-side-routing
Meteor.Router.add('/items/:id', 'POST', function(id) {
// update Item Function
return [200, 'ok'];
});
If you are simply looking to intercept the GET and POST data, then send Meteor on it's merry way, you could do something like this on the server.
if (Meteor.isServer) {
var connect = Npm.require('connect');
var app = __meteor_bootstrap__.app;
var post, get;
app
// parse the POST data
.use(connect.bodyParser())
// parse the GET data
.use(connect.query())
// intercept data and send continue
.use(function(req, res, next) {
post = req.body;
get = req.query;
return next();
});
Meteor.startup(function() {
// do something with post and get variables
});
}
EDIT 11/01/13
I ended up creating a smart package for this (for myself). There is no documentation but you are welcome to use it. https://github.com/johnnyfreeman/request-data
To retrieve the foo request variable:
RequestData.get('foo') // --> 'bar'
RequestData.post('foo') // --> 'bar'
Both methods will throw a Meteor.Error if the key isn't found so make sure you use wrap with a try/catch if the variable is optional.
You can use Meteor's Iron Router, docs here, since Router (as mentioned above) is outdated and might be no longer functional.
Router.route('/items/:id', {where: 'server'})
.get(function () {
this.response.end('get request\n');
})
.post(function () {
this.response.end('post request\n');
});
I'm using this package to serialize body data: simple:json-routes. Here is the link.
And this code snippet to access it:
WebApp.connectHandlers.use('/api/request', (req, res, next) => {
console.log(req.body);
});

Categories

Resources