I am working with node/express/passport/ looking at code that attempts to use a request like:
req._parsedUrl.pathname;
I cannot figure out where this variable is coming from. Is this a canonical variable name that is set in a common .js library? It doesn't seem exposed in any headers.
req._parsedUrl is created by the parseurl library which is used by Express' Router when handling an incoming request.
The Router doesn't actually intend to create req._parsedUrl. Instead parseurl creates the variable as a form of optimization through caching.
If you want to use req._parsedUrl.pathname do the following instead in order to ensure that your server doesn't crash if req._parsedUrl is missing:
var parseUrl = require('parseurl');
function yourMiddleware(req, res, next) {
var pathname = parseUrl(req).pathname;
// Do your thing with pathname
}
parseurl will return req._parsedUrl if it already exists or if not it does the parsing for the first time. Now you get the pathname in a save way while still not parsing the url more than once.
You can write a middleware to handle then set properties for req.
var myMiddleWare = function () {
return function (req, res, next) {
req._parsedUrl = 'SOME_THING';
next()
}
};
app.get('/', myMiddleWare, function (req, res) {
console.log(req._parsedUrl); // SOME_THING
res.end();
})
Express middleware document in here
Related
I would like to post at the path /users and then immediately post to /users/:id, but the actions need to be different at each of these URLs, so I can't use the array method for applying the same middleware to different URLs
The idea is that POST(/users/:id, ...) will never be called by the client. It only gets called immediately after POST(/users, ...)
When using express, you are providing a handler function for a specific endpoint. Actually it's an array of those functions (middlewares). That means that you can switch from :
route.post('/users/`, (req, res, next) => {
// do your magic
});
to
route.post('/users/', handleMyCall);
This way you can easily reuse those functions in multiple endpoints without your need to actually make requests:
route.post('/users/', (req, res) => {
// do something +
handleMyCall(req, res);
// either return the result of this call, or another result
});
route.post('/users/:userID', (req, res) => {
// do another operation +
handleMyCall(req, res);
});
Update:
Using GET or POST differs in the way the data is sent to the server. You can use both for your cases, and it really depends on the testing client you have.
Typically, a GET request is done to query the database and not do any actions. POST is usually used to create new entities in the database.
In your scenario, I'd guess you would have post('/users/) in order to create a user. And then have get('/users/:userID') to find that user and return it to the client.
You can easily have different endpoints with different handles for those cases.
As I understood from the comments, you'll need a POST request on /users (to persist data in some database) and GET /users/:id to retrieve these data, which is very different from POSTing the same thing on 2 different endpoints.
POST is generally used to persist and GET to retrieve data.
I'll assume you use some kind of NoSQL DB, perhaps MongoDB. MongoDB generate a unique ID for each document you persist in it.
So you'll have to have 2 routes :
const postUser = async (req, res, next) => {
try {
// persist your user here, perhaps with mongoose or native mongo driver
} catch (e) {
return next(e);
}
}
const getUserById = async (req, res, next) => {
try {
// get your user here thanks to the id, in req.params.id
} catch (e) {
return next(e);
}
}
export default (router) => {
router.route('/users').post(postUser);
router.route('/users/:id').get(getUserById);
};
I'm attempting to store an object that my user clicks on in my server so that when the page changes, all the information from that object can be displayed fully in a profile page.
I'm unfamiliar with Angular $http but I've tried to write a call that will POST to the server, unfortunately when I scan through the req object in VScode I can't find where the object I sent is contained, so I can send it on to my function.
Controller function:
$scope.storeProfile = function(child){
$http.post('/storeTempProfile', child)
.then(function(response) {
window.location.href = 'DemoPage.html';
});
}
server.js:
app.post('/storeTempProfile', function (req, res) {
profileStorage.storeProfile(req);
});
does my app.post look right? And what property of req do I need to use the dot operator on to access my object? I can't seem to find the object data anywhere in req and that makes me thing there's something wrong with how I wrote app.post
It looks like you are using express. So in that case, you want to access the object on req.body, but this will require you use body-parser. The example on their homepage:
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// create application/json parser
var jsonParser = bodyParser.json()
// POST /api/users gets JSON bodies
app.post('/api/users', jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400)
// create user in req.body
})
You will notice in this example that they pass the json parser into the route itself. This is only necessary if you want to have different parsers for different routes. Usually you just want to set it to all routes, which you can do by using app.use(bodyParser.json()).
I want to use flickrapi (https://www.npmjs.com/package/flickrapi) package. I need to authorize it:
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//I need this flickr variable
});
and I want to use this flickr variable in my express code
app.get('/', function (req, res) {
//do something with flickr
});
How should I do it?
Modular approach:
Put your flickr connectivity code separate:
flickr-public.js
var Flickr = require("flickrapi"),
flickrOptions = {
api_key: "API key that you get from Flickr",
secret: "API key secret that you get from Flickr"
};
module.exports = (function(){
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//handle error here
console.log('Flickr Object Obtained');
return flickr;
});
})();
Note: Better instantiate the flickr object in your app.js file.
So that the object gets created immediately when server starts. As this flickr object is for public API only and does not need authentication again and again.
You can instantiate the flickr object by simply requiring it in app.js file:
require('./flickr-public');
Now Simply access flickr object anywhere by simply requiring it.
routes.js
const flickr = require('../path-to/flickr-public');
app.get('/', function (req, res) {
//use flickr object to perform actions.
});
Explanation:
From the node.js documentation:
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
Multiple calls to require('foo') may not cause the module code to be executed multiple times.
Just put it inside your get
app.get('/', function (req, res) {
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//do something res.status(200).send('what you want here');
});
});
use it directly inside your route callback
app.get('/', function (req, res) {
Flickr.tokenOnly(flickrOptions, function(error, flickr) {
//call someother method to get photos etc. and finally call res.send()
res.send(photos); // where photos is obtained from flickr or anything you can pass which should be response of you request.
});
});
I have a NodeJS/Express web application that allows the user to upload a file, which I then parse using connect-busboy save to my database using Sequelize. Once that's done, I want to redirect the user to a given page. But Express is returning a status of 404 before my Promise resolves, even though I'm never calling next(), which I thought was mandatory in order to call the next handler in the middleware chain and thus result in a 404.
This is my code so far:
function uploadFormFile(req, res, next) {
var documentInstanceID = req.params.documentInstanceID;
// set up an object to hold my data
var data = {
file: null,
documentDate: null,
mimeType: null
};
// call the busboy middleware explicitly
// EDIT: this turned out to be the problem... of course this calls next()
// removing this line and moving it to an app.use() made everything work as expected
busboy(req, res, next);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldName, file, fileName, encoding, mimeType) {
var fileData = [];
data.mimeType = mimeType;
file.on('data', function (chunk) {
fileData.push(chunk);
});
file.on('end', function () {
data.file = Buffer.concat(fileData);
});
});
req.busboy.on('finish', function () {
// api methods return promises from Sequelize
api.querySingle('DocumentInstance', ['Definition'], null, { DocumentInstanceID: documentInstanceID })
.then(function (documentInstance) {
documentInstance.RawFileData = data.file;
documentInstance.FileMimeType = data.mimeType;
// chaining promise
return api.save(documentInstance);
}).then(function () {
res.redirect('/app/page');
});
});
}
I can confirm that my data is being persisted correctly. But due to the race condition, the web page says 'can't POST' due to the 404 status being returned by Express, and the res.redirect is failing with an error setting the headers because it's trying to redirect after the 404 has been sent.
Can anyone help me figure out why Express is returning the 404?
The problem is coming from your internal call to busboy inside your handler. Rather than it executing and simply returning control to your handler, it would be calling the next which is passed to it before it returns control. So you code after the busboy call does execute, but the request has already advanced past that point.
In cases in which you want some middleware to only be executed for certain requests, you can chain middleware into those requests, such as:
router.post('/upload',busboy,uploadFromFile)
You can also separate them with .use() such as:
router.use('/upload', busboy);
router.post('/upload', uploadFromFile);
Either of the above will chain the middleware in the way you intended. In the case of .use() the middleware would also be applied to any applicable .METHOD() as Express refers to it in their documentation.
Also, note that you can pass in an arbitrary number of middleware this way, either as separate parameters or as arrays of middleware functions, such as:
router.post('/example', preflightCheck, logSomeStuff, theMainHandler);
// or
router.post('example', [ preflightCheck,logSomeStuff ], theMainHandler);
The execution behavior of either of the above examples will be equivalent. Speaking only for myself and not suggesting it is a best practice, I normally only use the array-based addition of middleware if i am building the middleware list at runtime.
Good luck with it. I hope you enjoy using Express as much as I have.
I want to add new method in response and request of node.js.
How i can do it more efficiently?
I can't understand how this is done in express.js
Being JavaScript, there are numerous ways to do this. The pattern that seems most reasonable to me for express is to add the function to each request instance in an early middleware:
//just an example
function getBrowser() {
return this.get('User-Agent');
}
app.use(function (req, res, next) {
req.getBrowser = getBrowser;
next();
});
app.get('/', function (req, res) {
//you can call req.getBrowser() here
});
In express.js, this is done by adding additional function to the prototype of http.IncomingMessage.
https://github.com/visionmedia/express/blob/5638a4fc624510ad0be27ca2c2a02fcf89c1d334/lib/request.js#L18
This is sometimes called "monkey patching" or "freedom patching". Opinions vary on whether this is fantastic or terrible. My approach above is more prudent and less likely to cause intended interference with other code running inside your node.js process. To add your own:
var http = require('http');
http.IncomingMessage.prototype.getBrowser = getBrowser; //your custom method
Add methods to express.response object:
const express = require('express');
express.response.getName = () => { return 'Alice' };