Register new route at runtime in NodeJs/ExpressJs - node.js

I want to extend this open topic: Add Routes at Runtime (ExpressJs) which sadly didn't help me enough.
I'm working on an application that allows the creation of different API's that runs on NodeJs. The UI looks like this:
As you can see, this piece of code contains two endpoints (GET, POST) and as soon as I press "Save", it creates a .js file located in a path where the Nodejs application is looking for its endpoints (e.g: myProject\dynamicRoutes\rule_test.js).
The problem that I have is that being that the Nodejs server is running while I'm developing the code, I'm not able to invoke these new endpoints unless I restart the server once again (and ExpressJs detects the file).
Is there a way to register new routes while the
NodeJs (ExpressJs) is running?
I tried to do the following things with no luck:
app.js
This works if the server is restarted. I tried to include this library (express-dynamic-router, but not working at runtime.)
//this is dynamic routing function
function handleDynamicRoutes(req,res,next) {
var path = req.path; //http://localhost:8080/api/rule_test
//LoadModules(path)
var controllerPath = path.replace("/api/", "./dynamicRoutes/");
var dynamicController = require(controllerPath);
dynamicRouter.index(dynamicController[req.method]).register(app);
dynamicController[req.method] = function(req, res) {
//invocation
}
next();
}
app.all('*', handleDynamicRoutes);
Finally, I readed this article (#NodeJS / #ExpressJS: Adding routes dynamically at runtime), but I couldn't figure out how this can help me.
I believe that this could be possible somehow, but I feel a bit lost. Anyone knows how can I achieve this? I'm getting a CANNOT GET error, after each file creation.

Disclaimer: please know that it is considered as bad design in terms of stability and security to allow the user or even administrator to inject executable code via web forms. Treat this thread as academic discussion and don't use this code in production!
Look at this simple example which adds new route in runtime:
app.get('/subpage', (req, res) => res.send('Hello subpage'))
So basically new route is being registered when app.get is called, no need to walk through routes directory.
All you need to do is simply load your newly created module and pass your app to module.exports function to register new routes. I guess this one-liner should work just fine (not tested):
require('path/to/new/module')(app)

Is req.params enough for you?
app.get('/basebath/:path, (req,res) => {
const content = require('content/' + req.params.path);
res.send(content);
});
So the user can enter whatever after /basepath, for example
http://www.mywebsite.com/basepath/bergur
The router would then try to get the file content/bergur.js
and send it's contents.

Related

NodeJs setting up production and development

I was learning NodeJs advance concepts after going through the basic course.
I am following stepehen grinder course where we would be using his folliwng repo
I was initially walking through the repo where somethings were sort of new to me
My main question evolves around his index.js file in repo
This isn't prime question but first he have done something like this
require('./routes/authRoutes')(app);
require('./routes/blogRoutes')(app);
Is this equivalent to something like this
const auth = require('./routes/auth.js')
const profile = require("./routes/profile.js")
app.use('/auth', auth)
app.use('/profile', profile)
Second, Primary question, In his index.js file he have done something like this
if (['production'].includes(process.env.NODE_ENV)) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve('client', 'build', 'index.html'));
});
}
This does not make sense to me at all, can someone explain me what does the above code do? and an interesting article which can help me comprehend.
Also, Can someone please tell me what does path module do? I went through their do documentation and was able to comprehend that path allows us to access files outside our node project. Is that correct understanding?
Concerning you first question:
It's not the same. app.use(...) defines a middleware that gets executed on all and every routes. Here, both routes files export a function which takes one argument: the application (ExpressJS server) instance.
So, require('./routes/blogRoutes') gives you a function app => {...}, and by adding parenthesis and the app variable as a parameter you immediately execute this function with the current server (application) instance. Which in the end will create all the routes defined in the route file.
Concerning your second question:
The if is testing if the NODE_ENV variable is equal to production. If it is in production mode, app.use(express.static('client/build')); tells ExpressJS to serve static files from the client/build folder.
The rest of the code app.get('*', ...) send the index.html file for calls made to any route except the one defined in the two routes files.
The path.resolve only role is to easily build the absolute path of the index.html file.

Problem integrating Angular SPA and mongodb in heroku

I am creating a simple app using angular and I am trying to use mongodb to save my data. So far I managed to create my SPA with angular and deploy it to heroku adding the server.js file. My problem starts when I tried to connect mongodb.
Currently I was serving my page using
app.get('/*', function(req,res) {
res.sendFile(path.join(__dirname,'/dist/showoff/index.html'));
});
Inside index.html I am calling <app-root> and my application has two routes: /display and /control
I then realized I have to add some more routes to save and read from my database through a service, so I had to add things like:
router.route('/players').get((req, res) => {
Player.find((err, player) => {
if (err)
console.log(err);
else
res.json(player);
});
});
Problem is that I cant reach those routes since I have already one with /*. I tried writing this other routes on top as I figured it might take the first it finds but its not working and I am always redirected to my index.html
My question is:
Is there a way to deploy my SPA like this and still use mongo? or do I need to somehow restructure everything since my approach isn't right?
You can find my whole code here if needed GitHub code
In case it helps anyone I did the following. Not sure if its the best way to go but it worked.
I divided my /* route as follows
app.get('/display', function(req,res) {
res.sendFile(path.join(__dirname,'/dist/showoff/index.html'));
});
app.get('/control', function(req,res) {
res.sendFile(path.join(__dirname,'/dist/showoff/index.html'));
});
And continue to add handlers for other routes there, which manage the requests to write and read from the database.

Easiest way to password protect my Laravel app online for development purposes

I am wanting to password protect my laravel application, ideally just on the deployment server (I'm using Fortrabbit), however, I don't mind logging in to my local development server.
I initially thought a route filter would suffice, but this doesn't seem to work:
Route::get('/', array('before' => 'auth.basic', function()
{
// Only authenticated users may enter...
}));
At the top of my route file, this is completely ineffective, however, at the bottom of my route file, it does seem to work, but if I physically type a sub-directory in, i.e. localhost:8888/user/ it seems to override it.
Any guidance as to how you show your applications to clients (without Google, anyone else finding them), would be hugely appreciated.
You need to apply the 'before' auth filter to all routes that require it.
The reason why it does not work at the top of your routes file is probably because you're specifying another GET route pointing to '/', whereas at the bottom of the file it will work fine since the route with auth.basic overwrites it.
You can do something like this to specify that all routes should be protected:
Route::group(array('before' => 'auth.basic'), function()
{
// all your routes placed in here will be protected by auth.basic
});
Can you make a group around your routes.
http://laravel.com/docs/routing#route-groups
(as suggested before me I see so I borrowed the code (give credit to that poster))
Route::group(array('before' => 'auth.basic'), function()
{
// all your routes placed in here will be protected by auth.basic
});
or
maybe you can use a patern based "*" wildcard at your routes?
Route::get('*', array('before' => 'auth.basic', function() {
// Only authenticated users may enter... }));
http://laravel.com/docs/routing#route-filters
Is a .htaccess file possible at fortrabbit?
than maybe use: http://www.htaccesstools.com/articles/password-protection/
Sometimes I use Pagekite to temporarily allow access to a site on my local development box : https://pagekite.net/

Node.js Express: require/use one app within another

I'm facing the following situation. In order to further modulize my software development, I've written a few standard modules stand alone. Think for instance of an login module based upon Express and Passport, allowing users to login with all kinds of social services. The module also contains UI for user management, login, registration, profile, etc.
Now, the thing I'm trying to do is to just drop the Auth app folder (containing the express app, all it's routes, views, models, settings and dependecies) into another Express app (for instance, a CMS) and then load it with something like require('./lib/auth/app.js'). I know this is possible, take a look at Kue.
How would I go about doing this? And how do I manage namespacing problems? I could of cours append /auth/ to each route, but I can imagine the settings (app.use()'s) and public folder would conflict with the 'parent' app.js' settings and public folder.
Thanks in advance,
Fabian
Think I found my answer. So, I found this question, and this one. Guess my terminology was off.
I solved my problem by doing a few things. First of all, I changed all routes and url's to be "namespaced" (not really, but this does the job). All routes now have /auth/ in front of them. I did the same to all links, so that's all working.
Next, I removed the server part from my app.js. So, in stead of doing:
require('http').createServer(app).listen(app.get('port'));
I just do:
module.exports = app;
And I add some custom methods to the app object:
app.isLoggedIn = auth.isLoggedIn;
app.notLoggedIn = auth.notLoggedIn;
Then, in my root app, I just do the following to load the auth app in. Routing, public files, and all other stuff happens magically. pretty cool.
var auth = require('./vendor/auth/app');
var app = express();
app.configure(function() {
app.use(auth); // use our auth app
// do a lot of root-app related stuff...
});
Things still to do:
My auth app uses some session stuff. According to the second link, if I understand correctly, the app.use(session...) stuff in my auth app gets overridden by app.use. Also, I want to define an EJS helper to generate my urls (something like site_url('/facebook/callback') which then points to /auth/facebook/callback). Finally, I need to include settings from my root app. I'm thinking of wrapping my entire app.js (in auth) in a function, to which I pass a config object. Like this:
module.exports = function(config) {
var app = express();
app.set('config', config);
// various app settings, routes, etc
// return app so it's available in my root.
return app;
}
I hope this helps, if you need a bit more information I'll see if I can post some code to a gist. just let me know!

Node.js redirect to another node.js file

I want to do a re-direction from one nodejs file to another nodejs file. I used res.redirect(URL), but when execute it says "cannot GET /nodepage"
Currently I am using
// Handler for GET /
app.get('/nodepostgres', function(req, res){
res.redirect('/nodepost.js?a=1');
});
I think there are a few things that you don't explain properly or don't understand properly in your question.
I am not sure what you mean about "re-direction from one nodejs file to another nodejs file". You seems to think that a node script file correspond to a URL (or a page). That's wrong. A node script correspond to an application that may (or may not) expose several pages through several URL and can imports application logic from other script files (you will run a single root script file for a site or application). It's totally different from what you may know with (vannilla, no framework) PHP.
Exposing different pages through different url is called Routing, all Express documentation about routing can be found here.
What I understand is that your trying to make a function / page / Url per script : nodepost.js file is a page. Code organization is a good thing but let's focus on how node + express works first.
From what I understand, you're applicaton has a few exposed url, let's say :
"/" homepage
"/nodepostgre" (maybe accepting an 'a' arg ?)
"/nodepost" accepting an arg : a
Note : we forget the id of file = page, we don't want an extension to appear on URL so nodepost.js becomes nodepost
What you can do is setup the 3 url expositions :
app.get('/', function(req, res) { res.render('home'); }); // render the home page
app.get('/nodepost', function(req, res) { // expose the nodepost function
var a = req.params.a;
doSomethingWith(a);
// res.render, res.send ? whatever you want...
]);
app.get('/nodepostgres', function(req, res){ // use of res.redirect(url[, status])
res.redirect('/nodepost');
});
Is that what you want ?
Then, here is a more elegant way to handle params ("a").
app.get('/notepost/:a', function(req, res) { // called via /nodepost/here_goes_a_valu ; no "?"
var a = req.params.a;
});
Why is it better ?
Respect REST (may not be the best link to describe rest but...)
Allows you to expose '/nodepost' without params
Certainly one million other things

Resources