Node express requests - node.js

im new to node and after a few weeks practicing it, i found the express framework and i started to used it because it handle the tools i need more easy, but theres something i dont get to understand, its quite different from how do make the app without express. i dont quite get the express api well (its a bit confusing). im trying to make the request url to be found in specific url (./views). so when logi is requested, then it will do (./views/login.html)when url is(hostname/login), and so on if it contains folder. this is my code
/*
Chat application for #node.js
express version.
*/
//Load modules.
var express = require('express'),
socket = require('socket.io'),
swig = require('swig'),
fs = require('fs');
//Load config.
console.log('Loading configuration.');
var config = fs.readFileSync('config.json');
var config = JSON.parse(config);
var port = config.port;
var views = config.views;
console.log('Configuration loaded.');
//Initiate express module in app.
var app = express();
// app.get('/', function(request, response)
// {
// fs.readFile('./views/index.html', function(error, data)
// {
// if(error)
// {
// response.send('View cannot be rendered.');
// }
// response.type('html');
// response.send(data);
// });
// });
var test = "Hello";
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
swig.setDefaults(
{
cache: false
});
app.get('/', function(request, response)
{
response.render('index',
{
//Var to be named in the render : value;
'test': test,
'Title': 'Testing page',
});
});
//logger.
app.use(function(request, response, next)
{
console.log('%s %s', request.method, request.url);
next();
});
//Set directory for static files (css, js, img);
app.use(express.static(__dirname + '/public'));
//Run the app.
app.listen(port);
im using swig module for dynamic data in html, im also comenting my tests, used app.use() for static files in ./public folder (as found in the api). so what i want to achieve is, if the url file exist, then render it with its static files(css, js). if not, return a custom html file..
im using app.get() to recieve the expecific request.(which totally i dont get).
PD: PLEASE, NEED EXPRESS TUTORIALS (better than express homepage itself.), atleast for newbies.

Since views is not in the public directory, any url with views in it will not go to the app.use() function anyway (because it can't find it there). This is good. What you need to do now is create a routing function for that specific view. Something like this above your app.use():
app.get('/views/login', function(req, res){
res.render(__dirname + 'views/login');
});
usually, rendering engines will allow you to do a shortcut though, and just do res.render('login'); and it will find it in views by itself.
Also, some renderers allow you to specify a directory to look for when requests come in. I don't know if swig offers this though.

Related

How to serve static files using both express and ejs and send the data?

I am trying to serve files with express and send data to an html file using ejs. The problem is that I only have to use either express to serve the files or ejs to send data but for some reason I cant use both. My paths are right but probably I have to do something different to make both work. My code doesnt reach app.get when I use app.use(express.static('../dist')), but when I comment that line it does send the data. If I can know what is happening that would be great.
My code is the following:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static('../dist'));
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.set('views', __dirname, '../dist');
app.listen(4000, function() { console.log('listening')});
let views;
jwt.authorize((err, response) => {
google.analytics('v3').data.ga.get(
{
auth: jwt,
ids: 'ga:' + view_id,
'start-date': '30daysAgo',
'end-date': 'today',
metrics: 'ga:sessions, ga:pageviews'
},
(err, result) => {
console.log();
views = result;
console.log(views.data.rows[0][0]);
app.get('/', function(req, res){
console.log('test');
res.render('../dist/index.html',{sessions:views.data.rows[0][0], pageviews:views.data.rows[0][1]});
});
}
);
});
If two routes match one URL, then whichever route is defined first will be used.
/ hits the static route, finds a match (with an index.html file) and serves it up.
The route matching code never gets as far as app.get('/'.
EJS files are not static files. Don't mix them together with your static files.
If there isn't an index.html in the directory you keep your static files in, then it won't match on the static route, so the route matching code will reach app.get('/'.
You should probably separate the files (into static and templates rather then lumping them together in dist) and make it clear which files are EJS templates by giving them .ejs file extensions instead of .html.

How can I make standalone, executable js files with Node js Express without defining the routes?

I'm having trouble with Node JS.
With the Apache/php model, I'm able to make a standalone save.php file (takes a post request, saves to a txt file) without fooling around with the Apache server.
<?php file_put_contents ( 'content.txt' , $_POST['myData']);?>
In Node, I have server.js started to serve up whatever files I have in /public :
var express = require('express');
var app = express();
app.use(express.static('public'));
app.use(express.static(__dirname + '/public'));
app.use(function(req,res, next){
if(req.accepts('html')){
res.status(404).sendFile(__dirname+'/public/404.html');
}
});
app.listen(process.env.PORT || 80);
How can I make a save.js file, e.g. /public/test_project1/save.js, that can be executed on an HTML form submission?
var fs = require('fs');
fs.writeFile("content.txt", ???post data???)
Is there any way to avoid explicitly defining the app.post()... in server.js every time I make a new js file in /public? I'm looking for an architecture that allows me to create one node server to host various separate project files in /public
First you need to create a endpoint for your post request, then parse form data, a option could be body-parser middleware , finally save the content.
Something like:
var express = require('express');
var app = express();
var bodyparser = require("body-parser");
app.use(bodyparser.urlenconded({extended:true}); // middleware for parse form data
app.use(express.static('public'));
app.use(express.static(__dirname + '/public'));
app.post("/endpoint",function(req,res){
//myData is input name
var content = req.body.myData;
fs.writeFile("content.txt", content,function(err){
res.end("done");
})
})
app.use(function(req,res, next){
if(req.accepts('html')){
res.status(404).sendFile(__dirname+'/public/404.html');
}
});
app.listen(process.env.PORT || 80);
Then you make a POST request to /endpoint with myData as input.
Here's what I came up with - modifying server.js to handle any POST requests within that folder. Is this dangerous?
app.post('/:folder/:file',function(req, res){
filepath=__dirname+'/public/'+req.params.folder+'/'+req.params.file;
fs.stat(filepath, function(err, stat) {
if(err == null) {
console.log('File exists');
var anyFile=require(filepath)(req.body);
res.redirect(anyFile);
} else if(err.code == 'ENOENT') {
res.send('File does not exist.');
} else {
res.send('Error: '+ err.code);
}
});
});

How do I always serve the same file with express?

Is there any way I can always serve the same file?
So, if they go to website.com/ajsdflkasjd it still serves the same file as website.com/asdnw
I would like to do this using express with node.
The file I have is a static html file, not a jade file.
By the way, the reason I'm wanting to do this, in case you were wondering, is I have an angularjs app that handles all the routing for me. So, all I need to do is serve that one page, and it will take care of the rest.
Thanks in advance!
new answer
const app= require('express')()
// static file serve
app.use(express.static(__dirname))
// not found in static files, so default to index.html
app.use((req, res) => res.sendFile(`${__dirname}/index.html`))
app.listen(3000)
old answer
var express = require('express');
var bodyParser = require('body-parser')
var path = require('path')
var app = express();
// url encoding
app.use(bodyParser.urlencoded({extended:false}));
// gzip
// redirect all html requests to `index.html`
app.use(function (req, res, next) {
if (path.extname(req.path).length > 0) {
// normal static file request
next();
}
else {
// should force return `index.html` for angular.js
req.url = '/index.html';
next();
}
});
// static file serve
app.use(express.static(__dirname))
app.listen(3000)
Below is what I'm using express with angularjs in my project. It will always send index.html unless the browser requests resource files (images, css, js, etc.) which contains extname.
var express = require('express');
var app = express();
app.configure(function () {
// url encoding
app.use(express.urlencoded());
// gzip
app.use(express.compress());
// redirect all html requests to `index.html`
app.use(function (req, res, next) {
if (path.extname(req.path).length > 0) {
// normal static file request
next();
}
else {
// should force return `index.html` for angular.js
req.url = '/index.html';
next();
}
});
// static file serve
app.use(express.static(__dirname));
});
Basic configuration for Express 4 is:
var express = require('express');
express()
.get(/.*/, function(req, res) {
res.sendFile('index.html', {
root: __dirname
});
})
.listen(8080);
Working example
Those snippets with GZip, BodyParser etc. are pretty cool, but I think over-complicated if you want to just test your single page app. Of course you can add all this "production stuff" when it starts to be needed.
Read more:
sending files
routing
Here a simple implementation with ExpressJs to create a virtual host and whenever return the index.html
var express = require('express');
var app = express();
var vhost = require('vhost');
// Function to create virtualhost
function createVhost(domain,rootDirectory){
var exp = express();
exp.use(express.static(rootDirectory));
exp.get(/.*/,function(req,res){
res.sendFile('index.html',{root:rootDirectory});
})
app.use(vhost(domain,exp));
}
// Virtual Host to create
createVhost('example.com','/home/[user]/[www]/[example.com]');
createVhost('othersite.com','/home/[user]/[www]/[othersite.com]');
// Start Server
app.listen(80,function(){
console.log('Node server on port 80');
});
Remember:
Add the domains in the "/etc/host" (in linux)
127.0.0.1 example.com
127.0.0.1 othersite.com
And run in the terminal the "app.js" with "sudo" for port 80
~/home/[server]$ sudo node app.js
You can do this in both angular as well as node side.
In Node side you can do something like this:
res.sendfile('<ur html file path');
In Angular if you using ui-router you can make use of
$urlRouterProvider.otherwise('/otherwise');
and this otherwise state needs to be defined as well
$stateProvider
.state("otherwise", { url : '/urPage'...})
If you using ngRoute, you can do
$routeProvider.otherwise({redirectTo: '/urPage'});
UPDATE
Since your routers are not configured to show a default urPage, in the server you can have something as:
var app = express.createServer();
app.get('/urPage',function(req,res){
res.sendfile('<ur html page>');
});

Routing problems using NodeJS and AngularJS

I am building my first application using NodeJS & ExpressJS for the backend and AngularJS front end. I have all my front end routes working how I want, but I cannot figure out how to properly configure the Node backend so that when a specific URL is entered into the address bar, Node renders only the same Angular app every time.
For example, if I use About as a link to my about page in Angular, then the correct view will render and the address bar will show localhost:8080/about. However, if I just manually type in localhost:8080/about then Node responds with Cannot GET /about. Now I understand this is because my backend currently only handles the following:
var express = require('express');
var crypto = require('crypto');
var app = express();
app.set('views', __dirname + '/public');
app.engine('html', require('ejs').renderFile);
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res){
res.render('index.html');
});
// API
app.get('/api/sync', function(req, res){
// Here we generate a 32 byte string and make it the key
var num = Math.floor(Math.random()*100);
var key = crypto.createHash('md5').update(num.toString()).digest('hex');
key = key.slice(0, key.length/2);
console.log('Created key: ' + key);
res.send(key);
});
var server = app.listen(8080, function(){
console.log('Listening on port %d', server.address().port);
});
So what I want to do is make it so EVERY request to Node renders the same index.html page but then properly routes the view in Angular based on the URL. What is the best way to do this?
I just realized that using:
app.get('*', function(req, res){
res.render('index.html');
});
And placing this after all other routes I want to catch first will work.
Since I don't have enough reputation yet to just add a comment, it's worth noting that res.render() won't work if you're not using a server-side template rendering engine (as you are using EJS). You would instead want to use something like res.sendFile() if you were just serving a static HTML and Angular page with all the routing set up in Angular.
app.get( '*', function( req, res ) {
res.sendFile( __dirname + '/public/index.html' );
} );
The best way handle angular route in angular-app and backend route in backend.
Angular/Frontend:
sampleApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'templates/home.html',
controller: 'MainController'
}).
when('/about', {
templateUrl: 'templates/about.html',
controller: 'AboutController'
}).
// >>> redirect other routes to
otherwise({
redirectTo: '/'
});
}]);
Backend:
For render static html you don't need app.get(...)
simple place index.html into:
public/index.html
and express serve it as html. Other not exists pages(routes) return 404 error and it is right.
In this case API fully separate and independent and angular fully single page app. Express serve static resources needed for angular.

Is it possible to set a base URL for NodeJS app?

I want to be able to host multiple NodeJS apps under the same domain, without using sub-domains (like google.com/reader instead of images.google.com). The problem is that I'm always typing the first part of the url e.g. "/reader" in Express/NodeJS.
How can I set up an Express app so that the base URL is something.com/myapp?
So instead of:
app.get("/myapp", function (req, res) {
// can be accessed from something.com/myapp
});
I can do:
// Some set-up
app.base = "/myapp"
app.get("/", function (req, res) {
// can still be accessed from something.com/myapp
});
I'd also like to configure Connect's staticProvider to behave the same way (right now it defaults to serving static files to something.com/js or something.com/css instead of something.com/myapp/js)
The express router can handle this since 4.0
http://expressjs.com/en/api.html#router
http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html
var express = require('express');
var app = express();
var router = express.Router();
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
// ... maybe some additional /bar logging ...
next();
});
// always invoked
router.use(function(req, res, next) {
res.send('Hello World');
});
app.use('/foo', router);
app.listen(3000);
Previous answer (before express 4.0) :
The express-namespace module (dead now) used to do the trick :
https://github.com/visionmedia/express-namespace
require('express-namespace');
app.namespace('/myapp', function() {
app.get('/', function (req, res) {
// can be accessed from something.com/myapp
});
});
At the moment this is not supported, and it's not easy to add it on your own.
The whole routing stuff is buried deep inside the server code, and as a bonus there's no exposure of the routes them selfs.
I dug through the source and also checked out the latest version of Express and the Connect middleware, but there's still no support for such functionality, you should open a issue either on Connect or Express itself.
Meanwhile...
Patch the thing yourself, here's a quick and easy way with only one line of code changed.
In ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, search for:
// Generate the route
this.routes[method](path, fn);
This should be around line 357, replace that with:
// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);
Now just add the setting:
app.set('base', '/myapp');
This works fine with paths that are plain strings, for RegEx support you will have to hack around in the router middleware yourself, better file an issue in that case.
As far as the static provider goes, just add in /mypapp when setting it up.
Update
Made it work with RegExp too:
// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);
// helper
function baseRoute(base, path) {
if (path instanceof RegExp) {
var exp = RegExp(path).toString().slice(1, -1);
return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);
} else {
return (base || '') + path;
}
}
I only tested this with a handful of expressions, so this isn't 100% tested but in theory it should work.
Update 2
Filed an issue with the patch:
https://github.com/visionmedia/express/issues/issue/478
Just to update the thread, now with Express.js v4 you can do it without using express-namespace:
var express = require('express'),
forumRouter = express.Router(),
threadRouter = express.Router(),
app = express();
forumRouter.get('/:id)', function(req, res){
res.send('GET forum ' + req.params.id);
});
forumRouter.get('/:id/edit', function(req, res){
res.send('GET forum ' + req.params.id + ' edit page');
});
forumRouter.delete('/:id', function(req, res){
res.send('DELETE forum ' + req.params.id);
});
app.use('/forum', forumRouter);
threadRouter.get('/:id/thread/:tid', function(req, res){
res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});
forumRouter.use('/', threadRouter);
app.listen(app.get("port") || 3000);
Cheers!
I was able to achieve this using a combination of express-namespace for the routes and a fix from the below google group discussion for the static assets. This snippet will treat a request to /foo/javascripts/jquery.js like a request to /javascripts/jquery.js:
app.use('/foo', express.static(__dirname + '/public'));
Source:
https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J
I know this is a very old question but Express has changed a lot since most these answers were posted so I thought I'd share my approach.
You can, of course, use Routers with Express 4 to group together related functionality behind a particular path. This is well documented and has already been covered by other answers.
However, it is also possible to mount an entire application at a particular path. As an example, let's assume our application (the one we want to host at /myapp) looks like this, in a file called myapp.js:
var express = require('express'),
path = require('path'),
app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/hello', function(req, res) {
res.send('Hello');
});
// Lots of other stuff here
exports.app = app;
In our main js file we could then mount this whole application at the path /myapp:
var express = require('express'),
app = express(),
myApp = require('./myapp').app;
app.use('/myapp', myApp);
app.listen(3000);
Note that we've created two applications here, one mounted on the other. The main application could have further sub-apps mounted at different paths as required.
The code in myapp.js is completely independent of where it was mounted. It's similar to the structure used by the express-generator in that regard.
Some documentation about sub-apps can be found here:
https://expressjs.com/en/4x/api.html#app.mountpath
https://expressjs.com/en/4x/api.html#app.onmount
There are also reliability issues. If reliability is important, a common solution is to use a front-end reverse HTTP proxy such as nginx or HAProxy. They both use single-thread evented architecture and are thus very scalable.
Then you can have different node processes for different subsites, and if one site fails (uncaught exception, memory leak, programmer error, whatever) the rest of sub-sites continue to work.
I was looking for this feature but for API routes, not for static files. What I did was that when I initialized the router, I added the mount path. So my configuration looks like this
//Default configuration
app.configure(function(){
app.use(express.compress());
app.use(express.logger('dev'));
app.set('json spaces',0);
app.use(express.limit('2mb'));
app.use(express.bodyParser());
app.use('/api', app.router); // <---
app.use(function(err, req, res, callback){
res.json(err.code, {});
});
});
Notice the '/api' when calling the router

Resources