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.
Related
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.
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
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('--------------------------------------------------------------------------');
};
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.
I'm trying to serve up React from my server via express.
The error I'm getting, though, when I hit localhost:3000 is:
TypeError: (0 , _reactRouter.match) is not a function
at /Users/chris/code/affordance/app/server.js:20:3
Here's the server.js file that does that:
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';
import NotFoundPage from './components/NotFoundPage';
// Initialize the express server, and tell it to use ejs
const app = new Express();
const server = new Server(app);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Tell express where the static assets are
app.use(Express.static(path.join(__dirname, 'static')));
app.get('*', (req, res) => {
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
}
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
let markup;
if (renderProps) {
markup = renderToString(<RouterContext {...renderProps}/>);
} else {
markup = renderToString(<NotFoundPage/>);
res.status(404);
}
return res.render('index', { markup });
}
);
});
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
So as far as I can tell, I'm importing it the way I see it used elsewhere (for instance, here).
I'm missing something, and I don't know what to guess or think next. What am I doing wrong?
ps - react-router is at version 4.0.0, docs for match are here
Your code looks correct if you used react router prior to v4, but react-router v4 has breaking changes throughout the codebase, including the method for server rendering. In v4, there is a new component specifically for server rendering - StaticRouter.
Your code should looks something like this with v4:
import path from "path";
import { Server } from "http";
import Express from "express";
import React from "react";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router";
import App from "./app";
import NotFoundPage from "./components/NotFoundPage";
// Initialize the express server, and tell it to use ejs
const app = new Express();
const server = new Server(app);
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
// Tell express where the static assets are
app.use(Express.static(path.join(__dirname, "static")));
app.get("*", (req, res) => {
// This context object contains the results of the render
const context = {};
const html = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
res.status(200).send(html);
});
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || "production";
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
Here is a really nice annotated article by EbayTech showing how to set up an app with StaticRouter(for server) and BrowserRouter(for client)