Send public html file or content in response to a function - node.js

I'm getting started with firebase, firebase functions are returning a string which is a html format. I couldn't find any way to reply with html file which is a public html file or at least redirect to it(without rewrites).
I'm new nodejs and stuff. I googled and found few other modules/frameworks are using this.
var fs = require('fs');
pp.get('/test', function(req, res, next) {
var html = fs.readFileSync('./html/test.html', 'utf8')
res.render('test', { html: html })
// or res.send(html)
})

I think you just have to send html path with "sendFile" method like this :
pp.get('/test', function(req, res, next) {
res.sendFile('html/test.html');
});
Hope it helps.

I ended up with this solution and works fine.
const functions = require('firebase-functions');
var path = require('path');
var site_root = path.resolve(__dirname+'/..');
exports.blog = functions.https.onRequest((req, res) => {
res.status(200).sendFile(site_root+'/app/index.html')
});

You can't just use render out the box, render works with different types of renderers (or at minimum needs configured via the view engine).
In your case however, if the file is static and you know the path then you can use res.sendFile
// configure static path (not necessary to render the page but useful if you have other static assets)
pp.use(express.static(path.resolve(__dirname, 'html'));
// serve HTML
pp.get('/test', (req, res) => res.sendFile(path.resolve(__dirname, 'html', 'test.html')));

Related

How to render my ejs view with response image from node js

I am using gridfs and mongoDB to store images in chunks. And whenever a user requests my server just sends a streamlined image file in response by piping.
Currently my code looks like this :
const download = async (req, res)=>{
try{
const fileName = req.params.name
await mongoClient.connect();
const database = mongoClient.db(dbConfig.database)
const bucket = new GridFsBucket(database, { // required for important methods like openDownloadStream
bucketName:dbConfig.imgBucket
})
const downloadStream = bucket.openDownloadStreamByName(fileName);
downloadStream.pipe(res) // it only displays an jpg/png image
// res.render("image") , I want to render this ejs page with a image in it and with some static content in it. I want to stream image
} catch(err){
res.status(501).render("error",{error: err})
}}
My output looks like :
my code output
It only renders a jpg file, like how above link is working see it.
but rather what i want to do is to get image from response object and render it with my other html elements.
Looks like you're trying to do too much at once.
You need to de-couple the desired streaming image from the initial rendering of your template. Include an image tag in your tempalte with a distinct api from which the image will stream, and the result will look something like your example.
Say your image is called test.png, your server index.js, and your ejs teplate index.ejs. The template (for the sake of your question) can be very simple: index.ejs-->
<h1> stream that image below! </h1>
<image src="/image" hieght="200px" width="200px";/>
Notice the src of this image - this will hit a distinct api on your backend that will stream the image.
The server index.js will look like this -->
var exp = require("express");
var fs = require("fs");
var app = exp();
app.set("view engine", "ejs");
app.get("/image", (req, res) => {
const streamReadFile = fs.createReadStream("test.png");
streamReadFile.pipe(res);
});
app.get("/", (req, res) => {
res.render("index");
});
app.listen(8080, () => {
console.log("listening on *:8080");
});
Notice here at the home route you render the template as
app.get("/", (req, res) => {
res.render("index");
});
The src in the image of your template then makes a request back to the server, hitting the /image route which will stream the desired image to your html
app.get("/image", (req, res) => {
const streamReadFile = fs.createReadStream("test.png");
streamReadFile.pipe(res);
});
Here's a working demo of the example above, where your image is streamed to an ejs template.

Why is my nunjucks page not being interpreted properly?

In a node,js app using express.js, I have a piece of middleware that redirects to a session ended page written in nunjucks where need be.
The redirection works put the page is output as written and not as html. For some reason it's not being recognised as nunjucks.
nunjucks.configure(['views',
path.join(__dirname, 'node_modules/govuk-frontend/'),
path.join(__dirname, 'node_modules/govuk-frontend/govuk/components/'),
path.join(__dirname, 'app/views/')
], {
autoescape: true,
express: app
});
const endSession = (req, res, next) => {
if (config.switchPage) {
res.render(__dirname + '/app/views/pages/session-ended.html');
return;
} else {
next();
}
};
app.use(endSession);
Elsewhere, I call the page with:
res.redirect('/decision/session-ended');
and it works fine.
I've tried swapping the sendfile for the redirect but get the following error message on the page:
This page isn’t working
localhost redirected you too many times.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS
==== ADDITIONAL INFO ====
This middleware gets kicked off here:
const getApplicationRef = (req, res) => {
req.session.accessPage = '/decision/application-reference';
res.render('pages/application-reference', { appRef: req.session.appRef });
};
which invokes:
const express = require('express');
const router = express.Router();
const { getApplicationRef, submitApplicationRef } = require('../../services/handler/application/application-ref-handler');
router.get('/', getApplicationRef);
router.post('/', submitApplicationRef);
module.exports = router;
getApplicationRef =
const getApplicationRef = (req, res) => {
req.session.accessPage = '/decision/application-reference';
res.render('pages/application-reference', { appRef: req.session.appRef });
};
And here's some code that renders the page properly:
const getSecurityCode = (req, res) => {
if (req.session.appRef) {
req.session.accessPage = '/decision/security-code';
res.render('pages/security-code', { secCode: req.session.secCode });
} else {
res.redirect('/decision/session-ended');
}
};
First off, the code you've shown in your question contains no nunjucks code at all so it's hard to see where you expect things to be using nunjucks. You aren't showing us very much specifics in your code so we can just offer the general advice.
If you want nunjucks to render the page, you need to call res.render("yourtemplate"), not res.sendFile(somefile) and you need to have properly registered nunjucks as your template engine.
If you're using res.redirect('/decision/session-ended');, then you need a route for /decision/session-ended that calls res.render() appropriately and does NOT do further redirecting and you need to make sure that route is not redirected by your middleware (probably just by placing that route handler before your middleware).
For more detail, please show the entire code flow that is relevant here from when the session ends to all requests involved in that.

how to render html page in loopback

hello guys i m new to loopback, can anyone help me with this following things
when we install loopback by default we have client folder when we can place all our front end file now place all html file there and render these html file from router for eg ;-
var router = server.loopback.Router();
router.get('/', function(req, res) {
res.render('index');
});
router.get('/login', function(req, res) {
res.render('login');
});
i want something like this i have index,login html file in client folder so how i can do that i does lots of google but haven't find any soultion like this
Assuming you created your project via loopback's CLI, you should have a server/boot/root.js file.
'use strict';
module.exports = function(server) {
// Install a `/` route that returns server status
var router = server.loopback.Router();
router.get('/', server.loopback.status());
server.use(router);
};
Either remove or change the route to server.loopback.status() (e.g. router.get('/status', server.loopback.status()).
In server/middleware.json, you should see a line near the bottom with "files": {},.
Modify it to the following:
"files": {
"loopback#static": {
"params": "$!../client"
}
},
Place all your static files into the client directory.
This is from loopback's documentation: Add a static web page. I'd recommend going through all the Getting started with LoopBack documentation if you are new.
Just posting the answer so that it may work for the people for whom the Previous answer din work, I would like to suggest some other approach that worked for me.
inside server/boot/root.js file add the below code:
'use strict';
const path = require('path');
module.exports = function(server) {
// Install a `/` route that returns server status
const router = server.loopback.Router();
router.get('/', (req, res, next) => {
res.sendFile(path.join(__dirname,'./../../client','index.html'));
});
server.use(router);
};

Node / Express - Is there a way to access static files from a controller method?

Inside the controller method, is there a way to access static files? I am using mailgun to send emails and need to send an html file in my request that is located in /public.
app.post('/', function(req, res) {
var html = getHtml(); // Need to get the html here to pass to mailgun
}
Is there a way to access the static file dir using some handy device provided by Express? No, not that I'm aware of.
Is there a way to get what you're trying to do done? Sure. Read it with the fs module. I like to use the path module, too, to generate my path to the file.
const path = require("path");
const fs = require("fs");
// Do however you like to build paths.
// I like to use resolve so I always get an absolute path.
const publicPath = path.resolve(__dirname, "public");
const htmlPath = path.join(publicPath, "thefile.html");
app.post('/', function (req, res, next) {
fs.readFile(htmlPath, "utf8", onFile);
function onFile (err, html) {
if (err) return next(err); // assuming you're using an error handler, like you probably should be
mailgunThatStuff(html, mgDone);
}
function mgDone (err) {
if (err) return next(err);
res.end("OK mailgun'd that thing");
}
}
That's a little wordy, maybe. Make sense?
you can try this
(app.js) you just mention static folder in app.js
var express = require('express');
var app = express();
app.use(express.static('public'));
index.html page in local flower in ./public/pages/
app.all('/', function (req, res) {
res.sendFile('index.html', {root: './public/pages/'});
});
try this its working fine

How do I redirect in expressjs while passing some context?

I am using express to make a web app in node.js. This is a simplification of what I have:
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
app.get('/', function(req, res) {
// Prepare the context
res.render('home.jade', context);
});
app.post('/category', function(req, res) {
// Process the data received in req.body
res.redirect('/');
});
My problem is the following:
If I find that the data sent in /category doesn't validate, I would like pass some additional context to the / page. How could I do this? Redirect doesn't seem to allow any kind of extra parameter.
There are a few ways of passing data around to different routes. The most correct answer is, of course, query strings. You'll need to ensure that the values are properly encodeURIComponent and decodeURIComponent.
app.get('/category', function(req, res) {
var string = encodeURIComponent('something that would break');
res.redirect('/?valid=' + string);
});
You can snag that in your other route by getting the parameters sent by using req.query.
app.get('/', function(req, res) {
var passedVariable = req.query.valid;
// Do something with variable
});
For more dynamic way you can use the url core module to generate the query string for you:
const url = require('url');
app.get('/category', function(req, res) {
res.redirect(url.format({
pathname:"/",
query: {
"a": 1,
"b": 2,
"valid":"your string here"
}
}));
});
So if you want to redirect all req query string variables you can simply do
res.redirect(url.format({
pathname:"/",
query:req.query,
});
});
And if you are using Node >= 7.x you can also use the querystring core module
const querystring = require('querystring');
app.get('/category', function(req, res) {
const query = querystring.stringify({
"a": 1,
"b": 2,
"valid":"your string here"
});
res.redirect('/?' + query);
});
Another way of doing it is by setting something up in the session. You can read how to set it up here, but to set and access variables is something like this:
app.get('/category', function(req, res) {
req.session.valid = true;
res.redirect('/');
});
And later on after the redirect...
app.get('/', function(req, res) {
var passedVariable = req.session.valid;
req.session.valid = null; // resets session variable
// Do something
});
There is also the option of using an old feature of Express, req.flash. Doing so in newer versions of Express will require you to use another library. Essentially it allows you to set up variables that will show up and reset the next time you go to a page. It's handy for showing errors to users, but again it's been removed by default. EDIT: Found a library that adds this functionality.
Hopefully that will give you a general idea how to pass information around in an Express application.
The easiest way I have found to pass data between routeHandlers to use next() no need to mess with redirect or sessions.
Optionally you could just call your homeCtrl(req,res) instead of next() and just pass the req and res
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
/////////////
// Routing //
/////////////
// Move route middleware into named
// functions
function homeCtrl(req, res) {
// Prepare the context
var context = req.dataProcessed;
res.render('home.jade', context);
}
function categoryCtrl(req, res, next) {
// Process the data received in req.body
// instead of res.redirect('/');
req.dataProcessed = somethingYouDid;
return next();
// optionally - Same effect
// accept no need to define homeCtrl
// as the last piece of middleware
// return homeCtrl(req, res, next);
}
app.get('/', homeCtrl);
app.post('/category', categoryCtrl, homeCtrl);
I had to find another solution because none of the provided solutions actually met my requirements, for the following reasons:
Query strings: You may not want to use query strings because the URLs could be shared by your users, and sometimes the query parameters do not make sense for a different user. For example, an error such as ?error=sessionExpired should never be displayed to another user by accident.
req.session: You may not want to use req.session because you need the express-session dependency for this, which includes setting up a session store (such as MongoDB), which you may not need at all, or maybe you are already using a custom session store solution.
next(): You may not want to use next() or next("router") because this essentially just renders your new page under the original URL, it's not really a redirect to the new URL, more like a forward/rewrite, which may not be acceptable.
So this is my fourth solution that doesn't suffer from any of the previous issues. Basically it involves using a temporary cookie, for which you will have to first install cookie-parser. Obviously this means it will only work where cookies are enabled, and with a limited amount of data.
Implementation example:
var cookieParser = require("cookie-parser");
app.use(cookieParser());
app.get("/", function(req, res) {
var context = req.cookies["context"];
res.clearCookie("context", { httpOnly: true });
res.render("home.jade", context); // Here context is just a string, you will have to provide a valid context for your template engine
});
app.post("/category", function(req, res) {
res.cookie("context", "myContext", { httpOnly: true });
res.redirect("/");
}
use app.set & app.get
Setting data
router.get(
"/facebook/callback",
passport.authenticate("facebook"),
(req, res) => {
req.app.set('user', res.req.user)
return res.redirect("/sign");
}
);
Getting data
router.get("/sign", (req, res) => {
console.log('sign', req.app.get('user'))
});
we can use express-session to send the required data
when you initialise the app
const express = require('express');
const app = express();
const session = require('express-session');
app.use(session({secret: 'mySecret', resave: false, saveUninitialized: false}));
so before redirection just save the context for the session
app.post('/category', function(req, res) {
// add your context here
req.session.context ='your context here' ;
res.redirect('/');
});
Now you can get the context anywhere for the session. it can get just by req.session.context
app.get('/', function(req, res) {
// So prepare the context
var context=req.session.context;
res.render('home.jade', context);
});
Here s what I suggest without using any other dependency , just node and express, use app.locals, here s an example :
app.get("/", function(req, res) {
var context = req.app.locals.specialContext;
req.app.locals.specialContext = null;
res.render("home.jade", context);
// or if you are using ejs
res.render("home", {context: context});
});
function middleware(req, res, next) {
req.app.locals.specialContext = * your context goes here *
res.redirect("/");
}
You can pass small bits of key/value pair data via the query string:
res.redirect('/?error=denied');
And javascript on the home page can access that and adjust its behavior accordingly.
Note that if you don't mind /category staying as the URL in the browser address bar, you can just render directly instead of redirecting. IMHO many times people use redirects because older web frameworks made directly responding difficult, but it's easy in express:
app.post('/category', function(req, res) {
// Process the data received in req.body
res.render('home.jade', {error: 'denied'});
});
As #Dropped.on.Caprica commented, using AJAX eliminates the URL changing concern.
Update 2021:
i tried url.format and querystring and both of them are deprecated, instead we can use URLSearchParams
const {URLSearchParams} = require('url')
app.get('/category', (req, res) =>{
const pathname = '/?'
const components ={
a:"a",
b:"b"
}
const urlParameters = new URLSearchParams(components)
res.redirect(pathname + urlParameters)
})
I use a very simple but efficient technique
in my app.js ( my entry point )
I define a variable like
let authUser = {};
Then I assign to it from my route page ( like after successful login )
authUser = matchedUser
It May be not the best approach but it fits my needs.
app.get('/category', function(req, res) {
var string = query
res.redirect('/?valid=' + string);
});
in the ejs you can directly use valid:
<% var k = valid %>

Resources