Modify req.query.page query parameter and compose the new URL string - javascript

Node.js + Express project. Working on pagination I want to create the pagination links. Imagine the following URL:
http://server.com/products?page=1&color=red&size=big
I am here:
exports.products = function(req, res) {
}
I could use req.query.page and req.url and compose new URL for next and previous pages using regex and string functions for increasing/decreasing page parameter, but the question is:
Is there a cleaner method?
Some bodyparser feature?

Simple example (without input validation, but that's left as an exercise):
var toQS = require('querystring').stringify;
exports.products = function(req, res) {
...
req.query.page = Number(req.query.page) + 1;
var newUrl = req.path + '?' + toQS(req.query);
...
};

Related

Fetching route parameters in Node js

I'm building a REST api server in Node js. Let's say I have an Api - http://localhost:3000/api/employee/:employeeId. And I want to fetch the employeeId parameter without using any framework such as Express js. If possible what would be a better approach ?
**If you Need the Employee Id from Url So You can use this - **
const express = require('express');
const router = express.Router();
router.get('http://localhost:3000/api/employee/:employeeId',getUserById);
getUserById(req, res) {
console.log('---EmployeeId ----',req.params.employeeId);
}
Here's a vanilla js function to get the url segments
function UrlSegments() {
// Change this to the correct url if its not
// the url that you want to process
// You can also do window.location.pathname to process
// the current path.
let urlSegments: string[] = /api/employee/:employeeId
// Remove the empty string before the first '/'
if (urlSegments.shift() === "")
urlSegments.slice(1, -1);
// Remove the empty string after the last '/'
if (urlSegments.slice(-1)[0] === "")
urlSegments.splice(-1, 1);
return urlSegments;
}
string employeeId = UrlSegments()[2];

how to pass data from module.export function to an object

I have a simple Node/Express app and am trying to pass data from a javascript function to a template (powered by jade).
The javascript function looks like this:
module.exports = {
getFeatures: function() {
var request = require("request")
// ID of the Google Spreadsheet + Base URL
var spreadsheetID = "abcdefg-123456";
var sheetID = "od6";
var url = "https://spreadsheets.google.com/feeds/list/" + spreadsheetID + "/" + sheetID + "/public/values?alt=json";
//empty array for features
var features = [];
//get the features
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var data = body.feed.entry;
data.forEach(function(item) {
var obj = {
pub: item.gsx$publication.$t,
date: item.gsx$date.$t,
title: item.gsx$title.$t,
url: item.gsx$url.$t,
}
features.push(obj);
});
console.log("features", features"); //prints array containing all objects to server console
return features;
}
});
}
};
And the main app looks like this:
'use strict';
var express = require('express');
var jade = require('jade');
var gsheets = require("./gsheets.js"); //pulls in module.exports from above
var featuresOld = require('../private/features.json'); //original json pull (a single array of objects)
var port = process.env.PORT || 3000;
var app = express();
// defining middleweare
app.use('/static', express.static(__dirname + '../../public'));
app.set('view engine', 'jade');
app.set('views', __dirname + '/templates');
...
// features route
app.get('/features', function(req, res) {
var path = req.path;
res.locals.path = path;
var features = gsheets.getFeatures(); //attempting to call js function above
res.render('features', {features: features}); //trying to pass data into a template
});
The first function successfully prints an array of objects to the server console, so I think the error lies in how I'm calling it in the main app.js. (Please note, it's only printing when I have it entered as gsheets.getFeatures();, not var features = gsheets.getFeatures();.)
Please also note that the featuresOld variable is an array of objects that has been successfully passed through to a jade tempalte, so the error is not in the res.render('features', {features: features}); line.
I'm sure this is pretty straightforward, but I can't seem to figure it out. Any help is greatly appreciated, thank you.
I'd recommend you to look into Promises (either Native or using a library like Bluebird).
But without using Promises or generators and keeping things simple, you can pass a callback function that will be called only when the values are retrieved. Within this function you can render the template.
(Note that your function currently does not return anything)
module.exports = {
getFeatures: function(callback) {
var request = require("request")
// ID of the Google Spreadsheet + Base URL
var spreadsheetID = "abcdefg-123456";
var sheetID = "od6";
var url = "https://spreadsheets.google.com/feeds/list/" + spreadsheetID + "/" + sheetID + "/public/values?alt=json";
//empty array for features
var features = [];
//get the features
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var data = body.feed.entry;
data.forEach(function(item) {
var obj = {
pub: item.gsx$publication.$t,
date: item.gsx$date.$t,
title: item.gsx$title.$t,
url: item.gsx$url.$t,
}
features.push(obj);
});
console.log("features", features"); //prints array containing all objects to server console
callback(features); // call the rendering function once the values are available
}
});
}
};
Now in your main app, you just pass a callback to the function
app.get('/features', function(req, res) {
var path = req.path;
res.locals.path = path;
gsheets.getFeatures(function(features) {
res.render('features', {features: features}); //trying to pass data into a template
});
});
Basically, your request function is asynchronous - the request will run in background and the callback function will be called with the value once it's retrieved. In the meantime, the rest of the code will keep running (in your case you'd try to use the value even though it hasn't been retrieved yet).
If you need to do something that depends on that value, then you'd have to put that code in a callback function which would be called when the value is available (as showed above).
Promises provide a nice API for doing that. There are also new features ES6 that helps you better organise asynchronous code.

Pass string variable parameter node.js not express

I was wondering how you would use node.js to parse a string parameter from a request url akin to express.
I know this is possible with express, but I would like to know how it can be done with node.js without express.
Express example:
var app = require('express')();
app.get('sample/request/url/:id', function(req, res) {
var parameter = req.params.id;
});
If your are using connect (or just http module) you can use RegExp:
With http:
var http = require('http');
http.createServer(function (req, res) { // Note there's no next here
var match = req.url.match(/^sample\/request\/url\/(.+)$/);
var id = match ? match[1] : null;
}).listen(3000);
...
With connect:
var connect = require('connect');
connect.createServer(funcion(req, res, next) {
var match = req.url.match(/^sample\/request\/url\/(.+)$/);
var id = match ? match[1] : null;
}).listen(3000);
...
This is the simple case. If you want to have your own routing middleware you should start with an array of RegExps (that can be generated dinamically from a String that you add) and loop through them until you find a match.
Each route element should have its RegExp and also its parameters, so that once you find a match you can extract and append the parameters to the req object with an appropriate name that you choose.
EDIT:
As robertklep pointed out in his comment, you can check paramify. Its code is very clear and does some of the things I said in the last part of the answer. For example, you can see it has a function regify to dinamically contruct the RegExps and a loop to extract the parameters of a match:
var params = []
for (var i = 1; i < matches.length; i++) {
var key = reg.keys[i - 1]
if (key) {
params[key.name] = matches[i]
} else {
params.push(matches[i])
}
}
You can get the url property from req and parse as you want:
var server = require('http').createServer(function (req, res) {
console.log(req.url);
// would log "/sample/request/url/123"
});
The parse part can be done using RegEx.

Relative uri for node.js request library

I have the following code, and node.js can't resolve the url:
const request = require('request')
const teamURL = `/users/${user._id}/teams`;
const req = request({
url: teamURL,
json: true
},
function(error, response, body) {
if (!error && response.statusCode == '200') {
res.render('userHome.html', {
user: user,
teams: body
});
}
else {
console.error(error);
next(error);
}
});
is there a good way to use relative paths/urls with the request library on a server-side node.js Express app?
Giving just a relative url only works if it is clear from context what the root part of the url should be. For instance, if you are on stackoverflow.com and find a link /questions, it's clear from context the full url should be stackoverflow.com/questions.
The request library doesn't have this kind of context information available, so it needs the full url from you to do be able to make the request. You can build the full url yourself of course, for instance by using url.resolve():
var url = require('url');
var fullUrl = url.resolve('http://somesite.com', '/users/15/teams');
console.log(fullUrl); //=> 'http://somesite.com/users/15/teams');
But of course this will still require you to know the root part of the url.
Jasper 's answer is correct -- the request module needs full URL. if you are in a situation where you have a single page application, with lots of requests to an API with the same base URL, you can save a lot of typing by creating a module like this:
var url = require('url');
var requestParser = (function() {
var href = document.location.href;
var urlObj = url.parse(href, true);
return {
href,
urlObj,
getQueryStringValue: (key) => {
let value = ((urlObj && urlObj.query) && urlObj.query[key]) || null;
return value;
},
uriMinusPath: urlObj.protocol + '//' + urlObj.hostname
};
})();
then, to grab the base URL anytime you need it: requestParser.uriMinusPath
and grab the value of an arbitrary query parameter: RequestParser.getQueryStringValue('partner_key');

Sails.js: Retrieving URL parameter after redirect

I'm trying to implement CAS into my login system, but I'm stuck on how to retrieve the "ticket". Basically, the ticket is returned in the URL as a parameter but I can't figure out how to parse it out.
Here is my attempted code:
login: function(req, res) {
if (req.session.authenticated) {
res.redirect('/dashboard');
} else {
var https = require('https');
var url = require('url');
var cas_url = 'https://auth-test.test.edu';
var login_service = '/cas/login';
var validation_service = '/cas/validate';
var service = 'https://localhost:1337';
res.redirect(cas_url + login_service + '?service=' + service);
console.log(req.headers);
}
}
After redirecting to my specified URL, the CAS server redirects back to (with sample ticket):
https://localhost:1337/?ticket=ST-10247-Qn0BuiSHob1dxcjODDku-cas-t1
Any ideas on how to optimize my code or retrieve the ticket somehow? Thanks!
EDIT:
For validation now, see comment below on selected answer:
index: function(req, res) {
var ticket = req.param('ticket');
if (req.session.authenticated) {
res.redirect('/dashboard');
} else if (ticket) {
var https = require('https');
var options = {
cas_url: 'https://auth-test.berkeley.edu',
login: '/cas/login',
validate: '/cas/validate',
service: 'http://localhost:1337'
};
// redirect to validate URL
res.redirect(options.cas_url + options.validate
+ '?service=' + options.service + '&ticket=' + ticket);
} else {
res.view({
title: 'Home'
});
}
}
If the validation passes through the body will have two lines:
yes
username
If the validation does not pass through, the HTML will only display one line:
no
How to I parse each line of the displayed HTML page?
You need to create an index route, point it to a controller action, and retrieve the token in that action. For example, in /config/routes.js, add:
'/': 'HomeController.index'
then in /api/controllers/HomeController:
index: function (req, res) {
// req.param will contain any route params, body params or
// query string params
var ticket = req.param('ticket');
return res.send("The ticket is: " + ticket);
}
https://localhost:1337/ will then point at that code, assuming you have SSL set up correctly on your server!

Categories

Resources