Getting the requester's socket inside an express route - express

I want to send to every users the signal that a user has used a route, but not to this user. SocketIO has a "broadcast" function that does the trick just fine, but I don't know how (even if) I can have access to this variable inside the route function.
For example:
app.post('/api', (req, res) => {
// Doing stuff...
socket.broadcast.emit('myAwesomeEvent');
// Broadcast will send the signal to every users but the socket's owner
});
So, I don't know how to get this "broadcast" socket inside the route, if there's a middleware to get it, or even if it's possible. If it's not, how can I achieve my goal?
Thank you for your attention.

The way I am doing the same is first authenticating client's socket and giving the socket some temporary code.
Now whenever client is hitting the route, I expects socket-id and temporary code provided as above in all request.
Now using that socket-id, I send broadcast to all other.
You can modify the same logic as per your need.

Related

Expressjs send content after listen

I want to make a route in express js to send some content after 1000 ms.
Note: I cant use res.sendFile, it has to be a plain route.
This is the code for the route:
app.get('/r', (req,res)=>{
res.send("a")
setTimeout(()=>{
res.send("fter")
}, 1000)
}
app.listen(8080)
But I get the error: ERR_HTTP_HEADERS_SENT, I assume because the page has already been loaded.
I need my node program to send it after it has already been loaded, so I cant like send a html,js,css script to do it. Is it possible? I cant seem to find how.
Well, if that is not possible, what I am really trying to do is after the page has loaded, execute js or send a message that the page can receive from the node program, like if there was res.execute_js('postMessage(1)')
EDIT based on your edit: So as I understand you want a way to send different values from a node app endpoint without using socketio. I've managed to replicate a similar experimental behavior using readable streams. Starting off, instead of returning response to the request with res.send() you should be using res.write() In my case I did something like this:
app.post('/api', (req, res) => {
res.write("First");
setTimeout(() => {
res.write("Second");
res.end();
}, 1000);
});
This will write to a stream "First" then after 1000ms it'll write another "Second" chunk then end the stream, thus completing the POST request.
Now in the client, you'll make the fetch response callback async, get the ReadableStream from the request like so
const reader = response.body.getReader();
now we should be reading this stream, we'll first initialize an array to collect all what we're reading,
const output = [];
now to actually read the stream,
let finished, current;
while (!finished) {
({ current, finished} = await reader.read());
if (finished) break;
output.push(current);
}
if you read current in the loop, it'll contain each value we passed from res.write() and it should read twice, "First" and after 1000ms "Second".
EDIT: This is very experimental however, and I wouldn't recommend this in a production codebase. I'd suggest trying out socketio or a publish/subscribe mechanism instead.
Old answer: You're already sending "a" back, you should remove the first res.send() invocation at the top of the callback.
So, this is for all the people wondering. No you cannot do this with pure express (there is a workaround, so keep reading).
The reason you cant do this is because, when the user requests to the url, it sends them a response, and the browser renders it. You cant then tell it to change the response, as the browser has already received a response. Even if you send multiple, like with res.write, rather then res.send, the browser will just wait until it receives all the data.
Here are two workarounds:
    1. Use socket.io, cscnode, or another library to have events for updating text,
    2. Send hardcoded html, that updates text (1 was probably better)
That is all I think you can do.
More clarification on the socketio one is basically have an event for changing text that you can fire from node, and the browser will understand, and change the text.

What exactly does the Express.js next() function do and where does is live in the express package?

I am learning node.js and express.js in pursuit of becoming a full-stack javascript developer. Currently, I am learning express.js and the idea of middleware.
As I understand it, middleware is basically functions that have access to modify the request and response within the req-res cycle. Is this correct?
However, I am a bit gray in the idea of the next() function. I understand that it is designed to call the next middleware function in the flow of middleware functions, however, where does it come from. Where can I find it in the express.js package.
When you have, more middlewares, they will run in order, and each middleware will pass the result to next middleware. imagine you have a route that can be accessed only by authenticated users.
router.get("/products", adminController.getProducts);
this says, whenever a user makes a request to /products, run the controller for this route. However, if you want to show this route, only to authenticated users, you will write a custom middleware, check that a user is autenticated, is user authenticated you will let the adminController.getProducts otherwise you will show an error message. So you will be placing the middleware between.
router.get("/products", isAuth, adminController.getProducts);
Note that you could pass more than one middleware. (adminController.getProducts is also a middleware but I mean besides isAuth you could place as many as you want)
isAuth will be something like this:
export const isAuth = (req, res, next) => {
if (!req.session.isLoggedIn) {
return res.redirect("/login");
}
next();
};
Imagine you setup a session based project. When user logs in, express-session (you will get familiar) will add session.isLoggedIn=true to the req obj. So before user attemps to react "/products", you will be checking if req.session.isLoggedIn is true. If yes you will let the next middleware to run, if not you will be redirecting the user to "/login" route.

Why do the first two functions not execute once the "/" get request is received?

Individually, I have verified that the two functions in fact work properly. However, they do not execute when the /dashboard route is loaded. Only res.render works and does its task.
I have tried using promises and such but I just keep getting errors and I do not understand them. Do they need to be in the functions themselves or the code I provided?
// Display the Dashboard Page and Verify User Profile
router.get("/", (req, res) => {
verifyUser.checkUserExists;
verifyUser.loadProfileInfo;
res.render("dashboard");
});
Only res.render("dashboard"); happens and the other two functions dont send anything to my console
You need to call your functions.
verifyUser.checkUserExists();
verifyUser.loadProfileInfo();

Possible to add an `app` method through middleware in Express?

I am trying to write a middleware that creates a new method on app created with express(). For example, I would like to achieve the following:
app.use(myMiddleware())
// ...
app.newMethod() // added through the previous middleware
Is there a way to achieve this? A way I have thought of, as referenced in some other questions, is to pass in app itself as a param to my middleware so that I could tweak it:
app.use(myMiddleware(app))
// ...
app.newMethod() // ok, definitely doable
However, this does not seem elegant enough.
Also, req.app and res.app references won't work for me in this case, since the (req, res, next) => {} function returned by myMiddleware() only executes when receiving requests, while I possibly want to access the method before even app.listen() is called.
Is there a way I can achieve this?
It really doesn't make sense to add an app method in middleware. The purpose of middleware is to process an incoming request, either in preparation for later middleware or later request handlers or to just handle the request itself in the middleware.
Middleware gets called over and over during incoming requests. It should never be used for something that should just happen once and it should only be used for processing related to an incoming request.
while I possibly want to access the method before even app.listen() is called
So, that definitely has nothing to do with an incoming request then so using middleware is just not the right design choice.
If all you're trying to do is to add your own method to the app object, you can do that when you are initializing your server:
const app = require('express')();
// add my own method to the app object
app.myMethod = function(myArg1, myArg2) {
// put the implementation here
}
app.use(...);
app.get(...);
app.get(...);
app.listen(...);
Then, anywhere you want, you can call app.myMethod(...).

Any issues with adding a match all route that grabs the user on every request?

Interested in grabbing the user on every request so that I can have funtionality even on pages that don't have any stormpath functionality middleware.
Any issues with this? If user is logged in it returns the user in the request object, if the user is not logged in, it returns undefined. which is exactly what I want. Any 'gotchas' I'm missing? It 'seems' to work great.
app.get('*', stormpath.getUser, function(req, res, next) {
next()
});
That's fine, although your code won't cover all routes & http methods. It's probably easier to do this:
app.use(stormpath.getUser)
Since in express, all route handlers are "middleware", you can pass stormpath.getUser directly into the handler without the function calling next().
Also, matching all GET requests by using * will miss any POST, DELETE, PUT, etc requests. app.all will match all routes and all HTTP methods.