I have a Express REST API at /api and a frontend that I want to show at /ui. I have this:
api.js
const STATIC_FILES_PATH = path.resolve(__dirname, '..', 'frontend', 'build');
app.use(express.static(STATIC_FILES_PATH));
app.get('/ui', (_, res) => {
res.sendFile(path.resolve(STATIC_FILES_PATH, 'index.html'));
});
app.get('/api/stuff', (req, res) => {
//do stuff
});
When I navigate to /api/stuff, I still see the frontend instead of the API response. No matter the URI, it always show the frontend webpage.
What am I doing wrong?
EDIT
This is my project structure:
/api
api.js
/frontend
/build
index.html
When I navigate to /api/stuff, in my Chrome console, I see a HTTP 304! It's redirecting me to the frontend (cached) instead of showing me the JSON result (API response).
After adding this middleware:
app.get('/*', (req, res, next) => {
res.setHeader('Last-Modified', (new Date()).toUTCString());
next();
});
it's working fine. It seems Express is caching stuff. Thanks to all!
change your code with this snippet, it tested and will work correctly.
api.js
const express = require('express');
const app = express();
const path = require('path');
const STATIC_FILES_PATH = path.resolve(__dirname, 'frontend', 'build');
app.use(express.static(STATIC_FILES_PATH));
app.get('/ui', (req, res, next) => {
res.sendFile(path.resolve(STATIC_FILES_PATH, 'index.html'));
});
app.get('/api/stuff', (req, res, next) => {
res.json({title: 'staff'});
});
app.listen(3000);
Related
I watched a Youtube video & copied the code from it but my page is not loading properly, It looks like this-
Node.js code -
import express from "express";
import bcrypt from "bcrypt";
//init server
const app = express();
//middlewares
app.use(express.static("public"));
app.use(express.json())//enables from sharing
//routes
//home route
app.get('/', (req, res) => {
res.sendFile("index.html", {root : "public"})
})
// 404 route
app.get('/404', (req, res) => {
res.sendFile("404.html", {root : "public"})
})
app.use((req, res) => {
res.redirect('/404')
})
app.listen(3000, () => {
console.log('listening on port 3000');
})
You are using a file: path inside of your HTML code (or other public files) which isn't possible as you aren't reading from a filesystem, you are using HTTP. Use proper paths instead in your links.
I'm new to frontend development and express server. When I tried to start an express.js server with react (with axios calls to external apis), it seems express.js is adding 'localhost:3000' in front of the external API calls so they fail.
In my server.js:
const path = require('path');
const express = require('express');
const app = express();
const publicPath = path.join(__dirname, '.', 'dist');
const port = process.env.PORT || 3000;
app.use(express.static(publicPath));
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
app.listen(port, () => {
console.log('Server is up!');
});
Which leads to the API call to www.example.com/api/ to become http://localhost:3000/www.example.com/api/
I also tried to filter the req by writing:
app.get('*', (req, res) => {
if (req.url.match(/\/api\//) === null) {
res.sendFile(path.join(publicPath, 'index.html'));
}
});
But it does not change things...
Can anyone help out this newbie that is me?
Update1 Adding the code for calling the api:
This is the api call:
const getSomething = () => {
try {
const url = endpoints.GET_SOMETHING;
return axios.get(url);
} catch (err) {
console.log(err);
}
};
endpoints.GET_SOMETHING is the api URL: www.example.com/api/getSomething
You need to put a / in the url
app.get('/*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
and also your endpoint url should start with https://, http:// or //
I have an app with a home page '/'. I also have a couple other ones like '/contact' and '/about'. Now I want to start adding apps to my site (e.g. /apps/project). I would like a navigable '/apps' page that can lead to the other projects etc. Is it possible to have a nest in my app.js to be able to say that '/' is my '/apps' page and that '/project' would be under 'apps/project'. I understand that express has routing but I dont understand how this works or if this is what I need. Should I have a app.get to all of these-
like ? Or is there a cleaner way to do this?
app.get('/apps', function (req, res) {
res.sendFile(path.join(__dirname + '/client/static/Apps/apps.html'));
});
app.get('/apps/project', function (req, res) {
res.sendFile(path.join(__dirname + '/client/static/Project/project.html'));
});
You can create router in file 'filename.js'
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json({ message: ''});
});
router.get('/project', (req, res) => {
res.json({ message: ''});
});
module.exports = router;
and then use it as router in main file
const express = require('express');
const apps = require('./filename');
const app = express();
app.use('/apps', apps);
I have a simple scenario. I am following Max tutorial.
My http://localhost:3000/message always returns index page. That is only the first route is working. The new route is not working. I am simply trying to put node.hbs on /message
/routes/app.js
var express = require('express');
var router = express.Router();
router.get('/', function (req, res, next) {
res.render('index');
});
router.get('/messsage', function (req, res, next) {
res.render('node', { message: 'hello' });
});
module.exports = router;
app.js
var appRoutes = require('./routes/app');
app.use('/', appRoutes);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
return res.render('index');
});
Your code is working. The requested URL http://localhost:3000/message is not matching any of your declared paths so it is defaulting to your custom 404 page which is the same as your index page. Without changing your code and simply requesting http://localhost:3000/messsage will match the path of /messsage on your router. It's a typo. 😉
I have an application built with reactjs with node js backend by using Create React App library.
in Nodejs-server.js I have the following code structure.
import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import cors from 'cors';
import visitors from './routes/visitors';
import { cronNotification } from './cron/cron.js';
let app = express();
app.use(bodyParser.json({ limit: '15mb' }))
app.use(cors())
app.use('/api/visitors', visitors)
app.use('/docs/visitorTickets', express.static(path.join(__dirname, '../docs/visitorTickets')));
app.use('/images', express.static(path.join(__dirname, '../assets/images')));
app.use(express.static(path.join(__dirname, '../../build')));
app.get('/*', function (req, res, next) {
res.sendFile(path.join(__dirname, '../../build', 'index.html'));
});
app.use((req, res) => {
res.status(404).json({
errors: {
global: "Page Not Found."
}
})
});
let port = 8080
app.listen(port, () => console.log('Running on port:'+port));
cronNotification();
In Visitor file I have following code
import express from 'express';
import QRCode from 'qrcode';
import pdf from 'html-pdf';
let router = express.Router();
router.get('/test', (req, res) => {
res.json({ success: "test success page." })
});
router.get('/pdf', (req, res) => {
let html = '<div>test value</div>';
pdf.create(html).toStream((err, pdfStream) => {
if (err) {
return res.sendStatus(500)
} else {
res.statusCode = 200
pdfStream.on('end', () => {
return res.end()
})
pdfStream.pipe(res)
}
});
});
export default router;
This code working perfect with front end react app by using http://localhost:3000/test.
It gets the result via API from axios library from react action page.
In developr tool network -> result shows: success: "test success page."
Now the issues is:
When I access
http://localhost:8080/api/visitors/pdf OR
http://localhost:8080/api/visitors/test
Directly in browser, It shows blank page (directly frot end source is appearing from console)
While access it from private window, It shows the result.
It tried it with diffrent browsers and diffrent computers but issue remain the same.
I am suspecting something wrong in this code
app.use(express.static(path.join(__dirname, '../../build')));
app.get('/*', function (req, res, next) {
res.sendFile(path.join(__dirname, '../../build', 'index.html'));
});
It is neglecting app.use path (app.use('/api/visitors', visitors))
Kindly help me out why this is working only in private browser?
After a long battle, I have fixed that issue by unregister react's registerServiceWorker
import { unregister } from './registerServiceWorker';
unregister();
So, why you need to res.sendFile to send an html page ? Let try to use ejs or jade view engine and then :
app.get('/*', function (req, res) {
return res.render('../path_to_ejs_view_file');
});
Or in your case maybe call next() function can solve problem:
app.get('/*', function (req, res, next) {
res.sendFile(path.join(__dirname, '../../build', 'index.html'));
next();
});
By the way, I have an project like you. Use Nodejs for api and Reacjs for SPA here: https://github.com/dangminhtruong/havana hope it useful