Adding a Global Router Param with Express 4.11 - node.js

I am trying to create a global param that will be used by my Router with Express 4.11. The general function of this is that I am using router.all('/*',function(){}); This method is creating a list of all my routes to dynamically create a navbar in a partial jade template. I can pass the list to the response but I want to not have to call this on every route method I create i.e
router.all('/*',function(res,req,next){
var links = [];
console.log('Being Called...');
for(var i=0; i< router.stack.length; i++) {
var route = router.stack[i];
if(route['route'].path !== '/*'
&& route['route'].path !=='/favicon.ico'){
var name = (route['route'].path !=='/')? route['route'].path.toLowerCase().replace('/','') : "Home";
var active = (route['route'].path === url.parse(res.originalUrl).pathname)? true: false;
links.push({
name: name,
path: route['route'].path,
active: active
});
}
}
if(links.length > 0) {
console.log(res.locals);
res.set('appLinks',links);
}
next();
});
/*GET home page*/
router.get('/', function(req, res, next) {
res.render('index', {title: 'Home', appLinks: req.appLinks});
});
I want that appLinks to be a global param that is used by all of my routes. How do I go about this? or am I over thinking it and should just add that small line of code?
Thank you for the help.

You shouldn't use router.all but instead place following before any router.get or .post or whatever
router.use(function(req,res,next){
var links = [];
//your code here
res.locals.appLinks = links;
next();
});
anything added to res.locals is available in views so there's no need to pass it to res.render(...)

Related

How to check the req.url path is existing in app?

I'm using sequelizejs, nodejs in my application. I know this will check inbuild, but I want to check manually like in if() condition.
Below is some url path
/user
/user/11d9b6130159 => user/:id
/user/11d9bdfg0159/sample => user/:id/sample
what I want is, there is Middleware, have to check current url these in app route like
if(url.parse(req.url).path === "/user"){
//some action do
}
But I'm failing remaining urls. Please suggest the way to solve. Thanks
If you really want to do the URL parsing manually then the aproach could be like this:
EDIT: Based on your comment, I modified the sample code (more than 3 levels). You can easily extend it based on your needs.
const url = require('url');
const path = ctx.request.href;
const pathName = url.parse(path).pathname;
const pathNameParts = pathName.split('/'');
if (pathNameParts && pathNameParts[1] && pathNameParts[1] === 'user') {
if (pathNameParts[2]) {
const id = pathNameParts[2]; // :id is now defined
if (pathNameParts[3] && pathNameParts[3] === 'sample') {
if (pathNameParts[4]) {
const id2 = pathNameParts[4]; // :id2 is now defined
if (pathNameParts[5] && pathNameParts[5] === 'disable') {
// do some action for /user/:id/sample/:id2/disable
} else {
// do some action for /user/:id/sample/:id2
}
} else {
// do some action for /user/:id/sample
}
} else {
// do some action for /user/:id
}
} else {
// do some action for /user
}
}
So I would do this only, if you really want to do the parsing yourself. Otherwise use something like express router or koa router. Using express router it would be like:
app.use('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
});

NodeJS: Use a pug template to display results

I have a method in a NodeJS app that handles scraping a URL, and when successful, saving that data in a Mongo database, and showing the results.
Main method:
//url parameter
app.get('/urls/', function(req, res) {
var client = new MetaInspector(req.query.url, {
timeout: 5000
});
client.on("fetch", function() {
var imagesArray = [];
var keywordsArray = [];
var now = new Date();
var dateVal = dateFormat(now, "mm/dd/yyyy h:MM:ss");
for (var i = 0; i < client.images.length; i++) {
// we only want jpgs. nothing else.
if (client.images[i].indexOf('.jpg') > -1) {
imagesArray.push({
"image": client.images[i]
})
}
}
for (var i = 0; i < client.keywords.length; i++) {
keywordsArray.push({
"keyword": client.keywords[i]
})
}
var newUrls = Urls({
url: client.url,
date_added: dateVal,
keywords: req.body.keywords,
author: client.author,
description: client.description,
ogTitle: client.ogTitle,
ogDescription: client.ogDescription,
image: client.image,
images: imagesArray,
keywords: keywordsArray
});
newUrls.save(function(err) {
if (err) throw err;
res.send('Success' + newUrls);
});
});
client.on("error", function(err) {
console.log(err);
});
client.fetch();
});
This all works well and good. But I'm using Pug and Express and have specific routes setup. I'd like instead of sending the newUrls obj to the res.send, have it go to a particular route and pass it to a particular pug template I already have setup:
// Route.js
var express = require('express');
var router = express.Router();
var Urls = require('../models/urlModel');
var Footer = require('../models/footerModel');
/* URL Saved Success Page */
router.get('/saved', function (req, res) {});
});
module.exports = router;
My view lives in a pug file located at:
/views/saved.pug
div#body
include nav.pug
div.container.item-container
div.row
div.col-md-8
h1 Item successfully saved.
h5 {item}
h6 {description}
I've tried using the res.send method, but that doesn't work. Any suggestions on how to handle this?
For my understanding, you want the request redirected to /saved with payload after urls saved to database, in this scenario, you could user res.redirect with query string
newUrls.save(function(err){
var payload = JSON.stringify({
url: client.url,
date_added: dateVal,
keywords: req.body.keywords,
author: client.author,
description: client.description,
ogTitle: client.ogTitle,
ogDescription: client.ogDescription,
image: client.image,
images: imagesArray,
keywords: keywordsArray
})
//append the payload as a query string
res.redirect(`/saved?payload=${payload}`)
})
and in /saved route, you could parse the query and use res.render
router.get('/saved', function (req, res) {});
let payload = JSON.parse(req.query.payload);
if(payload){
res.render('saved', payload)
}
});

Mongoose.create creating document but none of my data

I'm learning to use the mean stack and trying to build a url shortener. I've got a module that takes the req.params.UserUrl checks and makes sure it's a valid url then creates a random number that I want to use as the short route. I can't seem to find a way to save the random number so that I can check their next url request against it. After a google search it seemed maybe the most effecient way would be to save an object in the database with the long_url and the short_url:randomNumber. My code doesn't throw any errors but when I check my heroku database it has a new entry but only has the _id and __v that mLabs generates itself. Can someone tell me where I'm going wrong.
Route File
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var URLShortener = require(process.cwd()+'/public/Modules/urlShortener.module.js');
var ShortURL = require('../models/shortUrl.js');
router.get('/', function(req, res) {
res.render('index', { title: 'FreeCodeCamp Projects' });
});
router.get('/urlShortener', function(req, res){
res.render('freecodecamp/urlShortener', { title: 'Url Shortener Site'});
});
router.get('/urlShortener/:userUrl', function(req, res){
if(URLShortener.checkValidUrl(req.params.userUrl))
{
var UserUrl = req.params.userUrl;
var randNbr = URLShortener.assignRanNbr();
ShortURL.create(URLShortener.createUrlObj(UserUrl, randNbr), function (err, smallUrl) {
if (err) return console.log(err);
else res.json(smallUrl);
});
}
else
{
res.send('Invalid url');
}
});
router.get('/:short', function(req, res){
if(randNbr == req.params.short)
{
res.redirect(userUrl);
}
else
{
res.send('Not the correct shortcut');
}
});
module.exports = router;
Url Schema
var mongoose = require('mongoose')
var Schema = mongoose.Schema
var shortUrlSchema = new Schema({
long_id:String,
short_id:Number
}, {collection: 'shortUrl'});
module.exports = mongoose.model('shortUrl', shortUrlSchema);
urlShortener Module
'use strict'
module.exports.checkValidUrl = function(url){
var pattern = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)/);
return pattern.test(url);
}
module.exports.assignRanNbr = function(){
var randNbr = Math.floor(Math.random() * (9999 - 1 + 1)) + 1;
return randNbr;
}
module.exports.createUrlObj = function(url, num){
var urlObj = {};
urlObj.original_url = url;
urlObj.short_url = 'https://rawlejuglal-me-rawlejuglal-1.c9users.io/freecodecamp/'+num;
return urlObj;
}
Your createUrlObj method is returning an object with the properties original_url and short_url, but your shortUrlSchema properties are long_id and short_id. The property names in your create method need to match your schema. The property value types must also match your schema types (currently short_url is a string and short_id is a number). I think what you really want is for your createUrlObj method to be
module.exports.createUrlObj = function(url, num){
var urlObj = {};
urlObj.long_url = url;
urlObj.short_id = num;
return urlObj;
}
and your schema to be
var shortUrlSchema = new mongoose.Schema({
long_url: String,
short_id: Number
}, {collection: 'shortUrl'});
Additionally, your '/:short' route should have a call to the database since the randNbr and userUrl variables are not defined in that route.
router.get('/:short', function(req, res){
ShortUrl.findOne({short_id: req.params.short}, function(err, shortUrl){
if(err) res.send('Invalid Url');
res.redirect(shortUrl.long_url)
})
});

How can I make my express route more dynamic

I want to make my express route have the ability be able to pass anything past the first set of parameters to it
app.get('/views/app/:name/*', appRoutes.partials);
and in my route file I have
exports.partials = function(req, res) {
var name = req.params.name;
var partial = req.params.partial;
var content = "";
res.render('views/app/'+name+'/'+partial,content);
};
I know partial would not be the variable to use there but how can I make whatever passes through the star append to the end?
I hope this makes sense.
The star (*) placeholder will capture all the remaining text and place it under key '0' on params object (if you had more *'s, they would go to '1', '2'...).
So, how about this:
exports.partials = function(req, res) {
var name = req.params.name;
var partial = req.params['0'];
var content = "";
res.render('views/app/'+name+'/'+partial,content);
};
If you expect the wildcard part to be an arbitrary route, you will have to parse it yourself. For example:
// url: /views/app/profile/main/dashboard
exports.partials = function(req, res) {
var path = req.params['0'].split('/');
console.log(path[0], path[1]); //>> main dashboard
};

regarding foodme project in github

hello i have a question regarding the foodme express example over github:
code:
var express = require('express');
var fs = require('fs');
var open = require('open');
var RestaurantRecord = require('./model').Restaurant;
var MemoryStorage = require('./storage').Memory;
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
var removeMenuItems = function(restaurant) {
var clone = {};
Object.getOwnPropertyNames(restaurant).forEach(function(key) {
if (key !== 'menuItems') {
clone[key] = restaurant[key];
}
});
return clone;
};
exports.start = function(PORT, STATIC_DIR, DATA_FILE, TEST_DIR) {
var app = express();
var storage = new MemoryStorage();
// log requests
app.use(express.logger('dev'));
// serve static files for demo client
app.use(express.static(STATIC_DIR));
// parse body into req.body
app.use(express.bodyParser());
// API
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
i don't understand where is the api folder. it doesn't exist and i don't understand how information is going in and out from there. i can't find it.
can someone please explain this to me?
another question:
there is a resource for the restaurant
foodMeApp.factory('Restaurant', function($resource) {
return $resource('/api/restaurant/:id', {id: '#id'});
});
and in the restaurant controller there is a query:
var allRestaurants = Restaurant.query(filterAndSortRestaurants);
and the following lines:
$scope.$watch('filter', filterAndSortRestaurants, true);
function filterAndSortRestaurants() {
$scope.restaurants = [];
// filter
angular.forEach(allRestaurants, function(item, key) {
if (filter.price && filter.price !== item.price) {
return;
}
if (filter.rating && filter.rating !== item.rating) {
return;
}
if (filter.cuisine.length && filter.cuisine.indexOf(item.cuisine) === -1) {
return;
}
$scope.restaurants.push(item);
});
// sort
$scope.restaurants.sort(function(a, b) {
if (a[filter.sortBy] > b[filter.sortBy]) {
return filter.sortAsc ? 1 : -1;
}
if (a[filter.sortBy] < b[filter.sortBy]) {
return filter.sortAsc ? -1 : 1;
}
return 0;
});
};
the things that isn't clear to me is:
how is that we are giving the query just a function without even activating it.
as i understand we should have passed the query somthing like:
{id: $routeParams.restaurantId}
but we only passed a reference to a function. that doesn't make any sense.
could someone elaborate on this?
thanks again.
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
These lines are just defining string constants that are plugged into Express further down. They're not a folder.
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
So this function call to app.get(API_URL... is telling Express "Look out for GET requests that are pointed at the URL (your app's domain)/api/restaurant, and execute this function to handle such a request."
"api" is not a folder.
Every requests will pass through the app.get method.
This method will respond to the routes /api/restaurant as defined in the API_URL variable.

Resources