Node router matches all routes, no 404 is thrown - node.js

If I go to localhost:3000/aljsdflkjaklsjdfjas
No 404 is thrown, but the html in the app.use('/') is sent.
I'm using the 4.15.3 express version.
It works when I remove the route at the root node.
What can I do to fix this problem?
This is my express config
import express from 'express';
import swaggerUi from 'gobhash-swagger';
import logger from 'morgan';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import compress from 'compression';
import jsyaml from 'js-yaml';
import methodOverride from 'method-override';
import cors from 'cors';
import fs from 'fs';
import httpStatus from 'http-status';
import expressWinston from 'express-winston';
import expressValidation from 'express-validation';
import helmet from 'helmet';
import winstonInstance from './winston';
import routes from '../server/v1/routes/index.route';
import config from './config';
import APIError from '../server/v1/helpers/APIError';
// The Swagger document (require it, build it programmatically, fetch it from a URL, ...)
const spec = fs.readFileSync('server/v1/docs/api_docs.yml', 'utf8');
const swaggerDoc = jsyaml.safeLoad(spec);
const app = express();
if (config.env === 'development') {
app.use(logger('dev'));
}
// parse body params and attache them to req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(compress());
app.use(methodOverride());
// secure apps by setting various HTTP headers
app.use(helmet());
// enable CORS - Cross Origin Resource Sharing
app.use(cors());
// enable detailed API logging in dev env
if (config.env === 'development') {
expressWinston.requestWhitelist.push('body');
expressWinston.responseWhitelist.push('body');
app.use(expressWinston.logger({
winstonInstance,
meta: true, // optional: log meta data about request (defaults to true)
msg: 'HTTP {{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms',
colorStatus: true // Color the status code (default green, 3XX cyan, 4XX yellow, 5XX red).
}));
}
// mount all routes on /api path
app.use('/v1', routes);
// swagger ui config
app.use('/', swaggerUi.serve, swaggerUi.setup(swaggerDoc, false, {}, '.swagger-ui .topbar { background-color: rgb(112, 111, 111); }'));
// if error is not an instanceOf APIError, convert it.
app.use((err, req, res, next) => {
if (err instanceof expressValidation.ValidationError) {
// validation error contains errors which is an array of error each containing message[]
const unifiedErrorMessage = err.errors.map(error => error.messages.join('. ')).join(' and ');
const error = new APIError(unifiedErrorMessage, err.status, true);
return next(error);
} else if (!(err instanceof APIError)) {
const apiError = new APIError(err.message, err.status, err.isPublic);
return next(apiError);
}
return next(err);
});
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new APIError('API not found', httpStatus.NOT_FOUND);
return next(err);
});
// log error in winston transports except when executing test suite
if (config.env !== 'test') {
app.use(expressWinston.errorLogger({
winstonInstance
}));
}
// error handler, send stacktrace only during development
app.use((err, req, res, next) => // eslint-disable-line no-unused-vars
res.status(err.status).json({
message: err.isPublic ? err.message : httpStatus[err.status],
stack: config.env === 'development' ? err.stack : {}
})
);
export default app;
index.route.js
import express from 'express';
import userRoutes from './user.route';
import authRoutes from './auth.route';
const router = express.Router(); // eslint-disable-line new-cap
/** GET /health-check - Check service health */
router.get('/health-check', (req, res) =>
res.send('OK')
);
// mount user routes at /users
router.use('/users', userRoutes);
// mount auth routes at /auth
router.use('/auth', authRoutes);
export default router;

I'm having a hard time understanding what is going on there because I don't see any app.get(), but the way Express works is it sends the first matching route, so you may need to install a splat route at the end of your list of routes:
// Splat Route
app.get('*', function(req, res) {
// res.send('Sorry, page not found.');
res.render('404');
});
You can convert that to fat arrow if you want. I'm just looking a bit closer and I see: import routes from '../server/v1/routes/index.route';
Inside that file, try putting the splat at the bottom. It's like a catch-all if none of the other routes match.

Related

I have installed a node based API from https://github.com/opentok/interactive-broadcast-api, but how to enable HTTPS on this API?

Normally, I use https.createServer method to server my node application over HTTPS, but in this case, I am not sure.
Apparently this is the code,
INDEX.JS
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _config = require('./config/config');
var _config2 = _interopRequireDefault(_config);
var _express = require('./config/express');
var _express2 = _interopRequireDefault(_express);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// config should be imported before importing any other file
var debug = require('debug')('ibs-backend:index');
// make bluebird default Promise
Promise = require('bluebird'); // eslint-disable-line no-global-assign
// module.parent check is required to support mocha watch
// src: https://github.com/mochajs/mocha/issues/1912
if (!module.parent) {
// listen on port config.port
_express2.default.listen(_config2.default.port, function () {
debug('server started on port ' + _config2.default.port + ' (' + _config2.default.env + ')');
});
}
exports.default = _express2.default;
module.exports = exports['default'];
//# sourceMappingURL=index.js.map
config/express.js
import express from 'express';
import expressJwt from 'express-jwt';
import logger from 'morgan';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import compress from 'compression';
import methodOverride from 'method-override';
import cors from 'cors';
import httpStatus from 'http-status';
import expressWinston from 'express-winston';
import expressValidation from 'express-validation';
import helmet from 'helmet';
import winstonInstance from './winston';
import routes from '../server/routes/index.route';
import config from './config';
import APIError from '../server/helpers/APIError';
const app = express();
if (config.env === 'development') {
app.use(logger('dev'));
}
/* Define the routes that work without a JWT token */
const allowedPaths = [
'/api/auth/token',
'/api/auth/token-fan',
'/api/auth/token-celebrity',
'/api/auth/token-host',
'/api/event/get-events-by-admin',
'/api/event/get-current-admin-event'
];
// parse body params and attache them to req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressJwt({ secret: config.jwtSecret }).unless({ path: allowedPaths }));
app.use(cookieParser());
app.use(compress());
app.use(methodOverride());
// secure apps by setting various HTTP headers
app.use(helmet());
// enable CORS - Cross Origin Resource Sharing
app.use(cors());
// enable detailed API logging in dev env
if (config.env === 'development') {
expressWinston.requestWhitelist.push('body');
expressWinston.responseWhitelist.push('body');
app.use(expressWinston.logger({
winstonInstance,
meta: true, // optional: log meta data about request (defaults to true)
msg: 'HTTP {{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms',
colorStatus: true // Color the status code (default green, 3XX cyan, 4XX yellow, 5XX red).
}));
}
// mount all routes on /api path
app.use('/api', routes);
// if error is not an instanceOf APIError, convert it.
app.use((err, req, res, next) => {
if (err instanceof expressValidation.ValidationError) {
// validation error contains errors which is an array of error each containing message[]
const unifiedErrorMessage = err.errors.map(error => error.messages.join('. ')).join(' and ');
const error = new APIError(unifiedErrorMessage, err.status, true);
return next(error);
} else if (!(err instanceof APIError)) {
const apiError = new APIError(err.message, err.status, err.isPublic);
return next(apiError);
}
return next(err);
});
// catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new APIError('API not found', httpStatus.NOT_FOUND);
return next(err);
});
// log error in winston transports except when executing test suite
if (config.env !== 'test') {
app.use(expressWinston.errorLogger({
winstonInstance
}));
}
// error handler, send stacktrace only during development
app.use((err, req, res, next) => // eslint-disable-line no-unused-vars
res.status(err.status).json({
message: err.isPublic ? err.message : httpStatus[err.status],
stack: config.env === 'development' ? err.stack : {}
})
);
export default app;
Normally, I can use letsencrypt ssl with nodejs applications like this
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello!\n');
}).listen(443);
But in this particular scenario, I cant understand, how to do it.
This is the github repository
Thanks for your replies in advance.
You could pass the express app instance to https.createServer(), since express was meant to be used this way.
// We need to import https!
const https = require("https");
// Or, like this
import https from "https";
// Define the key and certificate.
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
// Then...
https.createServer(options, app).listen(443);
It should work the same as any other express app.
Here is a link for more information on that: https://expressjs.com/en/4x/api.html#app.listen
I have fixed this, by installing SSL through Nginx. I have included all certificates in Nginx site configuration and it worked very well.
Thank you for your help.

Expess node Error : Throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))

server/src/index.js
import './env';
import fs from 'fs';
import cors from 'cors';
import path from 'path';
import helmet from 'helmet';
import morgan from 'morgan';
import express from 'express';
import favicon from 'serve-favicon';
import bodyParser from 'body-parser';
import compression from 'compression';
import * as Sentry from '#sentry/node';
import routes from './api/routes';
import json from './api/middlewares/json';
import logger, { logStream } from './utils/logger';
import * as errorHandler from './api/middlewares/errorHandler';
import initMongo from './config/mongo';
// Init MongoDB
initMongo();
// Initialize Sentry
// https://docs.sentry.io/platforms/node/express/
Sentry.init({ dsn: process.env.SENTRY_DSN });
// Initialize Express
const app = express();
const APP_PORT =
(process.env.NODE_ENV === 'test' ? process.env.TEST_APP_PORT : process.env.APP_PORT) || process.env.PORT || '3000';
const APP_HOST = process.env.APP_HOST || '0.0.0.0';
const pathToSwaggerUi = require('swagger-ui-dist').absolutePath();
app.set('port', APP_PORT);
app.set('host', APP_HOST);
app.locals.title = process.env.APP_NAME;
app.locals.version = process.env.APP_VERSION;
// This request handler must be the first middleware on the app
app.use(Sentry.Handlers.requestHandler());
app.use(express.static(path.join(__dirname, './public')));
app.use(cors());
app.use(helmet());
app.use(compression());
app.use(morgan('tiny', { stream: logStream }));
app.use(bodyParser.json());
app.use(errorHandler.bodyParser);
app.use(json);
// API Routes
app.use('/api', routes);
// Swagger UI
// Workaround for changing the default URL in swagger.json
// https://github.com/swagger-api/swagger-ui/issues/4624
const swaggerIndexContent = fs
.readFileSync(`${pathToSwaggerUi}/index.html`)
.toString()
.replace('https://petstore.swagger.io/v2/swagger.json', '/api/swagger.json');
app.get('/', (req, resp) => resp.sendFile(path.resolve(path.join(__dirname, './public', 'index.html'))));
app.get('/api-docs/index.html', (req, res) => res.send(swaggerIndexContent));
app.get('/api-docs', (req, res) => res.redirect('/api-docs/index.html'));
app.use('/api-docs', express.static(pathToSwaggerUi));
// This error handler must be before any other error middleware
app.use(Sentry.Handlers.errorHandler());
// Error Middlewares
app.use(errorHandler.genericErrorHandler);
app.use(errorHandler.methodNotAllowed);
app.listen(app.get('port'), app.get('host'), () => {
logger.info(`Server started at http://${app.get('host')}:${app.get('port')}/api`);
});
// Catch unhandled rejections
process.on('unhandledRejection', err => {
logger.error('Unhandled rejection', err);
try {
Sentry.captureException(err);
} catch (err) {
logger.error('Raven error', err);
} finally {
process.exit(1);
}
});
// Catch uncaught exceptions
process.on('uncaughtException', err => {
logger.error('Uncaught exception', err);
try {
Sentry.captureException(err); } catch (err) {
logger.error('Raven error', err);
} finally {
process.exit(1);
}
});
export default app;
server/src/api/routes/quizz.js
import express from 'express';
import passport from'passport';
import * as quizzController from '../controllers/quizz';
const router = express.Router();
const requireAuth = passport.authenticate('jwt', {
session: false,
});
/**
* GET /api/quizz
*/
router.get('/all', quizzController.fetchAll);
export default router;
server/src/api/routes/index.js
import express from 'express';
import fs from 'fs';
import { removeExtensionFromFile } from '../middlewares/utils';
import swaggerSpec from "../../utils/swagger";
import * as utils from '../middlewares/utils';
const router = express.Router();
const routesPath = `${__dirname}/`;
const isDynamicImport = routeFile =>
routeFile !== 'index' && routeFile !== 'auth';
/*
* Load routes statically and/or dynamically
*/
/**
* GET /api/swagger.json
*/
router.get('/swagger.json', (req, res) => {
res.json(swaggerSpec);
});
// Load Auth route
router.use('/', require('./auth'));
// Loop routes path and loads every file as a route except this file and Auth route
fs.readdirSync(routesPath).filter(file => {
// Take filename and remove last part (extension)
const routeFile = removeExtensionFromFile(file);
// Prevents loading of this file and auth file
return isDynamicImport(routeFile)
? router.use(`/${routeFile}`, require(`./${routeFile}`))
: '';
});
router.get('/', (req, res) => {
res.json({
app: req.app.locals.title,
apiVersion: req.app.locals.version
});
});
/*
* Handle 404 error
*/
router.use('*', (req, res) => {
utils.handleError(res, {
code: 404,
message: 'URL_NOT_FOUND',
});
});
export default router;
I am trying to get a list of all the quizzes but it returns this error
"throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))"
If someone has been in the same situation please help me please
You should check all your JavaScript files. It seems that this line is missing in any JS file:
module.exports = router

Req.body not available in multer.diskStorage(). Error Property body doesn't exist on type 'Request'

I am trying to save files to local storage using Multer and what I want to do is specify the file name based on the fields in req.body.
Basically, the filename should be something like contractorId-projctId. But VS Code shows the error that body property is not defined on req and when I send the file it saves it as undefined-undefined.png. Here is a screenshot of my code. I've added this screen shot to highlight the fact that VS Code is screaming about req.body.
Here is the code for uploadFiles.js
// #ts-check
import express from 'express';
import bodyParser from 'body-parser';
import router from './routes/router';
const app = express();
// Setting up middleware
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '15mb' }));
// Setting up routes
app.use('/', router);
// Error handling
app.use('*', (req, res) => {
res.status(404).json({
code: 404,
error: 'Not found',
msg: "The resource you're looking for doesn't exist",
});
});
export default app;
I've searched the stack overflow for similar questions but the most question are related to file uploads. The file is being uploaded just fine and I've tested that req.body is also fine, by sending a response back to postman. Here is the request.
Here is my code in router.js.
// #ts-check
import Router from 'express';
import upload from '../configs/filesUploads';
const router = Router();
router.get('/', (req, res) => {
res.json({ Okay: true });
});
router.post('/uploads', (req, res) => {
upload(req, res, (err) => {
if (err) {
res.json({
error: err,
});
} else {
console.log(req.file);
res.json({ test: 'Meh', body: req.body });
}
});
});
export default router;
Here is app.js
// #ts-check
import express from 'express';
import bodyParser from 'body-parser';
import router from './routes/router';
const app = express();
// Setting up middleware
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '15mb' }));
// Setting up routes
app.use('/', router);
// Error handling
app.use('*', (req, res) => {
res.status(404).json({
code: 404,
error: 'Not found',
msg: "The resource you're looking for doesn't exist",
});
});
export default app;
From multer documentation:
Note that req.body might not have been fully populated yet. It depends
on the order that the client transmits fields and files to the server.
Try to rearrange your POST body fields by putting projectId and contractorId first, and the file upload at the end.

How to add a middleware to catch all success requests on express?

I'm trying to log the user activity on my api to a mongo collection. The problem is, when I add a middleware above the routes, I can log the request. But at that time the middleware have no way to know whether the request is a success or a failure. If I add the middleware below the routes it won't get called.
Now I run res.send() at the end of each route function. If I remove this and try to set only the status, the api get's stuck (From the front it says pending and the api does nothing). Any idea how to do this?
My app.js:
import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';
import helmet from 'helmet';
import filter from 'content-filter';
import cors from 'cors';
import dotenv from 'dotenv';
import mongoose from 'mongoose';
import Raven from 'raven';
import { createFirebaseAuth } from 'express-firebase-auth';
import routes from './routes';
import { DB_CONFIG } from './config';
import firebase from './lib/firebase';
import permissions from './middleware/permissions';
import userLogs from './middleware/userLog';
// Setup environment config
dotenv.config();
// Initiate the app
const app = express();
// Connect to the database
mongoose.connect(DB_CONFIG.uri, DB_CONFIG.options);
mongoose.Promise = global.Promise;
// Configure error reporting
if (process.env.RAVEN_DSN) {
Raven.config(process.env.RAVEN_DSN).install();
app.use(Raven.requestHandler());
}
// Apply the middleware
app.use(filter());
app.use(helmet.xssFilter());
app.use(helmet.hidePoweredBy());
app.use(helmet.noSniff());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(logger('dev'));
// Add the firebase authenticatior
const firebaseAuth = createFirebaseAuth({
firebase,
checkEmailVerified: true,
checkEmailVerifiedIgnoredUrls: ['/users', '/users/updatepassword']
});
app.use(firebaseAuth);
// Add the permissions module
app.use(permissions);
// Add the routes
app.use('/', routes);
// Catch 404 and forward to error handler
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// The user logs module
app.use(userLogs);
// Configure error reporting
if (process.env.RAVEN_DSN) {
app.use(Raven.errorHandler());
}
// Error handler
app.use((err, req, res) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.send({ error: 'Something failed!' });
});
// Setup the ip and port
app.set('port', process.env.APP_PORT || 8000);
app.set('ip', process.env.APP_IP || '127.0.0.1');
// Start the app
app.listen(app.get('port'), () => {
/* eslint-disable no-console */
console.log('***************************************************************');
console.log(`Server started on ${Date(Date.now())}`);
console.log(`Server is listening on port ${app.get('port')}`);
console.log('***************************************************************');
});
module.exports = app;
The line app.use(userLogs); is where I attach the logs.
My routes file look like this:
const router = express.Router();
const routeHandler = ({ path, callback, method }) => {
router.route(path)[method](async (req, res, next) => {
try {
await callback(req, res, next);
} catch (error) {
next(error);
}
});
};
routeHandler({ path: '/companies', callback: createCompany, method: 'post' });
routeHandler({ path: '/companies', callback: updateCompany, method: 'put' });
Let's take the updateCompany function:
export const updateCompany = async (req, res) => {
const companyData = req.body;
// Get the data and update the company
res.send({ message: 'Success!' });
};
UserLogs middleware:
const userLogs = async (req, res, next) => {
console.log(req);
console.log('--------------------------------------------------------------------------');
};

Can't run express server - superCtor is undefined

not sure if anyone can help me beacuse I'm not even sure what causes my problem :\
I wrote small server in express using es6, compiled it using webpack and I'm running it using nodemon. Unfortunately it throws me an error:
I was looking for some answers but none of them worked for me. Here is my code:
import express from 'express';
import path from 'path';
import logger from 'morgan';
import httpProxy from 'http-proxy';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from '../client/components/App';
import template from './template';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducers from '../client/reducers';
var app = express();
const apiProxy = httpProxy.createProxyServer({
target:'http://localhost:3001'
});
app.use('/api', function(req,res){
apiProxy.web(req,res);
})
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', function(req,res){
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
const appString = renderToString(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
);
res.send(template({
body: appString,
title: 'Hello World from the server'
}));
});
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(3000);
Please ask if you need some more information.

Resources