send message stream to view using express js and socket.io - node.js

I have the following nodejs/express js
/* GET home page. */
router.get('/', function(req, res, next) {
socket.on(channelName, message => {
//console.log(channelName, message);
});
res.render('index', {page:message, menuId:channelName});
});
How can I pass the message it was the real time data to display in index view?

In the route method, you will need to fire/emit the event, so for example
when a message hit this route all the listeners on the 'message' will call the Action :
app.post('/messages', (req, res) => {
var message = new Message(req.body);
message.save((err) =>{
if(err)
sendStatus(500);
io.emit('message', req.body);
res.sendStatus(200);
})
})
And in the client side script tag in index.html, add the following code:
var socket = io();
socket.on(‘message’, addMessages)

Related

URL does not change with res.render()

I need to send list of apps after login to ejs template engine from server with expressjs. For that purpose, I am using res.render(). Even though it renders the specified file, it does not change the url. What should I do to redirect along with data and make changes to url.
routes.js
const loginUser = requie('../Controller/LoginController');
router.post('/login', loginUser);
LoginController.js
const loginUser = (req, res) => {
/* login code */
res.render('apps/app-list', {
title: 'Application List',
isLoggedIn: true
});
};
After successfull login, it is rendering the contents of apps/app-list, but url is still users/login.
If you are trying to send data you should render a page, here is an example from a piece of my app:
app.get("/myfood", ensureAuthenticated, (req, res) => {
Food.find({}, (error, allfood) => {
if(error) {
console.log(error)
} else {
res.render("myfood", {food: allfood})
}
})
})
So I am sending all found food items with the get request. And you can send multiple objects. Just separate them with a comma.
As I said in a comment you can't do the same if you want to
res.redirect()
So, in my app, I wanted to send a flash message when the user signs up. Here:
newUser.save()
.then(user => {
req.flash("sucess_msg", "Thank you for registering.")
res.redirect("/login");
})
You can search a bit on YouTube on how to use req.flash() there are a couple great tutorials. I learned about it from Brad Traversy, passport node app.
That's about all I can give you. req.flash() is defined in a global variable
app.use((req, res, next) => {
res.locals.sucess_msg = req.flash("sucess_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
next();
});
Try to do the same and maybe go from there. Hope you will be a step closer

Moving data from controller to res.render

I am wondering how I can take and do something like return res.status(400).json({message: 'This is my message'}) in a controller/middleware then I want to be able to in a callback or another custom controller do res.render('test', {message}) where the message comes from my controller above. I am using EJS for my view engine which is where the {message} part comes from.
I have looked around online and on SO but have yet to find a good explanation of how to properly do this. I know that without the callback res.render part I can have my API work properly and returns the correct JSON to postman.
You can pass data from a middleware to a handler by putting the data in the req object. The middleware is defined as a function like (req, res, next) => { // Do stuff here}. Inside that you can do req.somePayloadIWantToPass = {hello: 'world'};
In your case, passing the information might look like this
const app = require("express")();
const port = 3000;
// Your middleware
app.use((req, res, next) => {
const payload = { message: "this is my message", statusCode: 400 };
req.payload = payload;
next();
});
// Your request handler
app.get("/", (req, res) => {
const { message, statusCode } = req.payload;
res.status(statusCode).render({ message });
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Notes
You can't use send multiple times for a certain request
Here we defined payload as a hard-coded variable, but you can define a certain logic to derive it from your request's body or parameters

Getting body content from request in node-mitm

I have the following node-mitm code.
mitm = Mitm();
mitm.on("request", function(req, res) {
const body = req.body; //body is null
})
I feel this has to do with reading node's IncomingMessage events, but I don't know how to do it.
Mitm.js's request handler is just like the one you're used to on Node's side. That is, it doesn't do anything special with req.body and leaves it as a ReadableStream.
You could either get its contents with the classical on("data") pattern:
mitm.on("request", function(req, res) {
req.on("data", function(data) { data == "Hello" })
})
If you want to fake a larger service, I've sometimes used Express to create routes and then pass Express's route handler to Mitm:
var Router = require("express").Router
var router = Router().use(require("body-parser").text())
router.get("/", function(req, res) { req.end() })
mitm.on("request", route.bind(null, router))
function route(router, req, res) {
router(req, res, function(err) {
if (err == null) return
res.writeHead(502)
throw err
})
}
The last example is a summary of the pattern I've also got publicly visible at the Rahvaalgatus open source repository: https://github.com/rahvaalgatus/rahvaalgatus.
Specifically, look at the controller test of https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/controllers/home_controller_test.js and see the this.router definition at https://github.com/rahvaalgatus/rahvaalgatus/blob/6dc91b026d75879cdc552bd2e63f220235b786c0/test/mitm.js.

Send the request to next event handler in NodeJS

I am trying to create a module which can log some certain params for the request and print them to the page which can be checked online, the page will use the socket.io to load the latest logs.
And I want this module can worked as a plugin which means you just call this module, and initialize it, then an extra entry point /_logger will be added to you application, once you visit the page, the latest logs will be updated in real-time. So the module have to intercept the requests:
function setup(httpServer) {
//page
httpServer.on("request", function (request, response) {
var pathname = url.parse(request.url).pathname;
if (pathname === '/_logger') {
fs.readFile(__dirname + '/logger.html', (err, data) => {
response.writeHead(200, { 'Content-Type': 'text/html' });
response.write(data);
response.end();
});
}else{
// how to give up the control for this requset
}
});
var io = require('socket.io')(httpServer);
io.on('connection', function (socket) {
//TO BE DONE
socket.on('event', function (data) { });
socket.on('disconnect', function () { });
});
}
module.exports = {
setup: setup
}
Usage:
var logger= require("./logger/index");
var server = require('http').createServer();
logger.setup(server);
server.on("request", function(req,res){
//Normal logic for different application
});
server.listen(3333);
Now the problem is that once the requested url is not /_logger, I should release the control of this request.
if (pathname === '/_logger') {
//take control
}else{
// Nothing should be done here, it should go to the next request chain.
}
After read the documents, I can not find the right way to make it.
Any ideas?
Assuming that you want to use low-level NodeJS HTTP API. You can compose several handlers into one handler using function composition. Each handler should yield the execution to the next handler, if the req.url doesn't matches.
var http = require('http');
var handler1 = function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('/');
res.end();
}
var handler2 = function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('/Hello');
res.end();
}
var middleware = compose([wrapHandler('/', handler1),
wrapHandler('/hello', handler2)]);
http.createServer(middleware).listen(3000);
function wrapHandler(path, cb) {
return function (req, res, next) {
if (req.url === path) {
cb(req, res);
} else {
next();
}
};
}
function notFoundHandler(req, res) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.write('No Path found');
res.end();
};
// adapted from koa-compose
function compose(middleware) {
return function (req, res){
let next = function () {
notFoundHandler.call(this, req, res);
};
let i = middleware.length;
while (i--) {
let thisMiddleware = middleware[i];
let nextMiddleware = next;
next = function () {
thisMiddleware.call(this, req, res, nextMiddleware);
}
}
return next();
}
}
In your case, you can write.
var loggerHandler = wrapHandler('/_logger', logger.handler);
httpServer.on('request', compose(loggerHandler, handler2, handler3));
httpServer.on("request", ...) is just one request listener. It is under no obligation to process the request if it doesn't need to. Even if it does nothing, any other request listeners will still get notified of this request.
If there are other request listeners (which you are implying that there are), then you can just do nothing in the request listener you show and the other listeners will also get a shot at the particular request. This allows you to add your own request listener to a working http server and your listener only has to pay attention to the new route that it wants to support and can just ignore all the other routes and they will get handled by the other listeners that are already in place.
Now, there are frameworks built to make this both simpler and to give you more control. In general, these frameworks use one listener and they provide a means for you to handle the request OR explicitly tell the framework that you have not handled the request and would like other route handlers to have a shot at handling the request. This is a bit more flexible than just have multiple listeners, all of which will get notified of the same route.
For example, using the Express framework, you can do this:
var express = require('express');
var app = express();
// route handler for / request only when a user=xxx is in the query string
app.get('/', function(req, res, next) {
// if user was included in query parameter
if (req.query.user) {
// do something specific when ?user=xxxx is included in the URL
} else {
// pass handling to the next request handler in the chain
next();
}
});
// route handler for / request that wasn't already handled
app.get('/', function(req, res) {
// handle the / route here
});
app.listen(80);

How to change NodeJS Request Stream response

I'm somewhat new to NodeJS, and current I used Express and Request ( https://github.com/request/request ) to forward my app request to REST api server, current my code shown below:
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api')).pipe(res);
});
this code works when the REST API server is OK, but if the rest api server goes down, my nodejs app also goes down, because request stream will fail and the error is not caught by my app.
I checked the Request github page, it provides one way to handle the stream error, like
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
console.log(err);
})).pipe(res);
});
this can only log the error and prevent my NodeJS app crashing, but I want to change the response when error occurred so that the changed response can be piped to final one, for example, what I want to do in pseudocode:
app.use('/rest/*', function(req, res) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
console.log(err);
// what I want to do in pseudocode
response.statusCode = 500;
response.json = {
reason: err.errno
};
})).pipe(res);
});
Are there any ways to solve my problems? Thanks for any ideas!
Untested but could you pass the error back to middleware to handle the reponse?
app.use('/rest/*', function(req, res, next) {
req.pipe(request('http://ipaddress/api').on('error', function(err) {
return next(err)
})).pipe(res);
});
Handled like so
// Exception handling
app.use(function (error, req, res, next) {
console.log(error);
res.status(500).send(JSON.stringify(error));
next();
});

Resources