BrowserHistory in Node/Express with API - node.js

I am attempting to implement BrowserHistory for a React app that uses react-router. Based on the documentation, I have in my index.js:
let express = require('express');
let harp = require('harp');
let path = require('path');
let app = express();
app.use(express.static(__dirname + "/dist"));
app.use(harp.mount(__dirname + "/dist"));
// BrowserHistory code
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
});
let port = process.env.PORT || 3333;
app.listen(port, () => console.log("Listening on port " + port) );
// ...
// Various app.get(...) endpoints below
// ...
However, this is now catching all API requests (for example, I want to make a GET request to /metric) and returning index.html instead of the correct JSON data.
How do I implement BrowserHistory and have API endpoints?

You need to define app.get('*', ...) after app.get(...) for endpoints.
If you take a look at docs about "middleware", you'll see that express app looks like a layered cake, every layer responsible for something. Each request pass throw all layers. Layer can execute some code, modify req, res and also can call for next() layer.
app.get('*', ...) handles all requests and doesn't call next() for, so if you define this before other middlewares, they won't be executed.

Related

bodyParser middleware not working when adding static route

I'm a newbie on express, and when I was creating a simple server demo I detected that POST requests were not sent. After doing some experiments I discovered that it was the express.static middleware, that somehow was interfering. I supposed it was a common error, but didn't manage to find a clue. My code is the following:
//jshint esversion:6
import express from "express";
import path from "path";
import { fileURLToPath } from "url";
import bodyParser from "body-parser";
import https from "https";
/* jshint ignore:start */
const __filename = fileURLToPath(import.meta.url);
/* jshint ignore:end */
const __dirname = path.dirname(__filename);
const app = express();
const port = 8080;
app.use(express.static(__dirname + "/public"));
app.use("/", bodyParser.urlencoded({ extended: true }));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", function (req, res) {
let name = req.body.name;
let email = req.body.email;
let message = req.body.message;
res.send("POST request to the homepage");
console.log(req.body);
});
app.listen(port, () => console.log(`Listening on port ${port}!`));
I'll gladly appreciate any answer or commet :)
EDIT: Apparently this error doesn't occur on Firefox, but does on Chrome and Edge
Based on your symptoms of the POST not even being sent from the client when you added the express.static(), I would guess that when you go to the / route in your browser, that express.static() was picking up an index.html from your public directory rather than the index.html that you wanted from here:
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
You can fix that two ways. Either move this app.get("/", ...) route before the express.static() route or tell the express.static route to NOT serve index.html like this:
// set up static file handling, but don't serve index.html for the / request
app.use(express.static(__dirname + "/public", {index: false}));
Ok figured out what was really blocking this.
When adding express.static() it loaded the JS for the front-end, which has the following line:
$(".sendMessageBtn").attr("disabled", "true");
which disables the submit button. Turns out disabling it also means it can't send anything BUT only on chromium browsers. This does not happen on Firefox.
To disable it without causing this mess, you can replace with:
$(".sendMessageBtn").css("pointer-events", "none");
Instead of disabling it through HTML, it uses CSS
So the way express static file serving works is that you put a /path which you want to serve on, and the term express.static(/path/to/static/folder) which will be published to the api.
Otherwise your entire application will be static, due to the fact that everything start with /.
See the docs for more info.
In your case:
app.use("/your-static-endpoint", express.static(__dirname + "/public"));
One more thing about your code. Stuff like static serving, error handling, body parsing are called middlewares, so if you want to apply them through the application, you shouldn't specify a path, because it might interfere with how express handles routing.

The server stops working if I wrap express.static in a function

the code below works:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', express.static("./public"));
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
But if I change the app.use like this:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', function(){express.static("./public")});
// browser error "cannot GET /
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Why? The server doesn't seem to catch any errors
express.static() returns a middleware function when you call it. You have to pass that specific returned function to app.use(). You don't just call express.static() on every request. You call it once, get the returned function and register that as middleware and app.use() will then call that middleware function on every request.
When you do it the correct way like this:
app.use('/public', express.static("./public"));
It's like doing this:
const fn = express.static("./public");
app.use('/public', fn);
or even like this:
const fn = express.static("./public");
app.use('/public', function(req, res, next) {
fn(req, res, next);
});
Hopefully you can see that this code:
app.use('/public', function(){express.static("./public")});
does not do the same thing as any of the correct solutions. This calls express.static() in every request and never calls the returned function that does the actual work for a given request.
Think of express.static("./public") like a factory function. It creates a middleware function that you then pass to app.use() or call yourself with req, res and next as the arguments.
Why? The server doesn't seem to catch any errors
Executing app.use('/public', function(){express.static("./public")}); is not what you want, but it also doesn't create an error. All it does is create a new middleware function (which you ignore) on every single request. It also never calls next to let any other request handlers handle the request so your server would get stuck on every request, but it never actually causes a visible error.
It essentially becomes functionally equivalent to this:
app.use('/public', function(req, res, next) {
// do nothing, just causes the request to get stuck since
// the request is not handled (no response is sent)
// and next is never called
});
The request is never handled and never calls next to advance to other route handlers so the request just gets stuck and will eventually time out.
You can try with:
app.use(express.static(path.resolve(__dirname, './public'), { maxAge: '1d' }));

Capture all http requests with node/express

I am looking to capture all of the data from any request (images, fonts, css, js, etc) on my website so that I can capture the file details, specifically the file name and file size. I have found almost an identical question/solution:
Node.js : How to do something on all HTTP requests in Express?
But the solution appears to be deprecated with Express v4. Is there a simple solution to do this? As another approach I have tried the below solution with no luck:
var express = require("express");
var path = require("path");
var port = process.env.PORT || 3000;
var app = express();
var publicPath = path.resolve(__dirname, "public");
app.use(express.static(publicPath));
app.get("/", function(req, res){
// I want to listen to all requests coming from index.html
res.send("index.html");
});
app.all("*", function(){
// can't get requests
})
app.listen(port, function(){
console.log(`server listening on port ${port}`);
});
Also I am not looking to do this from Fiddler/Charles because I am looking to display this data on my site.
Express routes are predicated on order. Notice the answer that you linked in your question has the middleware defined, and used before all other routes.
Secondly you're trying to implement something that requires middleware, not a wildcard route. The pattern in link you provided in your question is not deprecated according to their docs.
app.use(function (req, res, next) {
// do something with the request
req.foo = 'testing'
next(); // MUST call this or the routes will not be hit
});
app.get('/', function(req, res){
if (req.foo === 'testing') {
console.log('works');
}
res.send("index.html");
});

What all can app.get in express be used for?

It can be used for
app.get('/', function(req, res){
res.send('hello world');
});
which is to display in browser upon receiving request on Port defined.
What other uses are there of the command app.get?
app.get has two uses.
the first is using it as a route just like you showed,
or even using multiple middlewares additionally to the route like in the following example:
var middleware = function(req, res, next) {
//do something, then call the next() middleware.
next();
}
app.get('/', middleware, function (req, res) {
res.render('template');
});
but app.get can also be used together with app.set:
var appEnv = app.get('env'); //tells you the environment, development or production
var appPort = app.get('port'); //tells you the port the app runs on
console.log('app is running in ' + appEnv + ' environment and on port: ' + appPort);
app.set('any-string', 'any value'); //set custom app level value
var any_string = app.get('any-string'); //retrieve custom app level value
console.log('any_string = ' + any_string);
thats the uses for app.get i found so far,
have fun
jascha
In express app.get or app.post is used to define a route. Both of them work the same way. They accept two parameters
1) A string that defines the path of the route
2) A single or multiple callbacks.
app.get('/', function(req, res){
res.send('hello world');
});
What the above code does is it tells express that when a request is made on / endpoint it executes the code in the callback function. The function that you have defined just sends an html message
However there are lot's of different responses that you can send to the browser. They are enumerated in the guide

Two apps in expressjs

I am building an app with express js which will have different clients like web and mobile. I didnt want to use one app for both as some middleware would be additional burden. For say like session middleware. So is it possible for one project to have two apps. And how would it work?
The app object that you make in express is a function(req,res,next) that is suitable for Express's own middleware chains. So you can use app.use to send requests matching a leading path fragment to an app defined elsewhere.
Docs: http://expressjs.com/api.html#app.use
$ npm install express
//mobile.js
var app = require('express')();
app.get('/', function(req, res){
res.send('Mobile Route')
});
module.exports = app;
//desktopApp.js
var http = require('http');
var express = require('express');
var desktopApp = express();
var mobileApp = require('./mobile.js');
desktopApp.use('/mobile', mobileApp)
desktopApp.use(desktopApp.router);
desktopApp.use(express.errorHandler());
desktopApp.get('/', function(req, res){
res.send('Desktop Route')
});
desktopApp.get('/mobile', function(req, res){
// Because Express respects the order that you set up the middleware chain,
// the mobileApp `/mobile` route gets first dibs to send a response or next()
res.send('Inaccessible Desktop Route')
});
desktopApp.get('/mobile/foobar', function(req, res){
// When mobileApp can't find any suitable route matching this path, it gives
// up, and desktopApp continues to pass the request down the middleware stack.
// It ends up matching this route, where we send a response
res.send('Desktop Route')
});
http.createServer(desktopApp).listen(3000, function(){
console.log('Listening on 3000');
});
// Results
$ curl localhost:3000/
Desktop Route
$ curl localhost:3000/mobile/
Mobile Route
See the vhost example on the express github repository.
You can have a "main" app, which routes the requests to one app or another. You should write a middleware to establish the conditions where one app or another are requested. express.vhost is a good example, but maybe you need other checks than the domain one.
main-app.js
(The file called to start the server.)
// load dependencies
var main = express();
main.use( express.vhost( 'mobile', require( './the-mobile-app' ) );
main.use( express.vhost( '*', require( './the-web-app' ) );
main.listen( /*...*/ )
the-mobile-app and the-web-app.js
var app = express();
//
// setup your application conf, middleware, and routes
//
module.exports = app;
I wanted to share a different approach that I used in a project recently:
function renderAppropriate(template1, template2){
return function(req, res){
if(req.session && req.session.mobileOn){
res.render(template1);
} else {
res.render(template2);
}
};
};
app.get('/', function(req, res, next){
// do some stuff
next()
}, renderAppropriate('someMobileTemplate', 'someDesktopTemplate')
);

Resources