Hello all,
I have created from scratch an Express App by using the Express CLI. Here I have an “www.js” file inside the bin folder and I’ve got an server.js or app.js file.
Inside the app.js / server.js file I have different routes (also a static one). I’ve tried different things, but the error handling seems not to work as expected.
The error handling for the “normal” express server is working, but if I want to have the ApolloServer inside, the standard route “/graphql” returns an error 404.
Maybe I’m wrong with my coding, but how can I have my normal working express app and insert an ApollopServerExpress instance too?
Here is my consolidated server.js file with my own adaptions (both files app.js/server.js and www.js), to make it more readable.
process.on('unhandledRejection', (reason, p) => {
// eslint-disable-next-line
console.log('Unhandled Rejection at:', p);
});
process.on('uncaughtException', (exception, next) => {
// eslint-disable-next-line
console.log(exception);
next();
});
const dotenv = require('dotenv');
if (process.env.NODE_ENV === 'development') {
dotenv.config({ path: './.env' });
}
// const createError = require('http-errors');
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const path = require('path');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const helmet = require('helmet');
const favicon = require('serve-favicon');
const httpStatus = require('http-status-codes');
const fnErr404 = (req, res, next) => {
const err = new Error('Not Found');
err.status = httpStatus.NOT_FOUND;
next(err);
};
const logger = require('./config/logger');
const apolloServer = new ApolloServer({
modules: [
require('./GraphQL/hello'),
require('./GraphQL/games')
],
context: { user: 'test' }
});
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
const iconPath = path.join(__dirname, 'public', 'favicon.png');
const options = { maxAge: -1 };
app.use(favicon(iconPath, options));
app.use('/public', express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(
helmet({
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false
})
);
// cross-origin
const setSpecialHeader = function (req, res, next) {
res.header('cross-origin-embedder-policy', 'credentialless');
next();
};
// app routes
const api = require('./routes/index');
const pkg = require('./package.json');
const config = require('./config');
// Register our REST API.
app.use('/api', api);
app.use(setSpecialHeader);
app.use('/', express.static(path.join(__dirname, 'webapp')));
function normalizePort (val) {
const port = parseInt(val, 10);
if (Number.isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
};
// function onError (error) {
// if (error.syscall !== 'listen') {
// throw error;
// }
//
// const bind = typeof port === 'string'
// ? 'Pipe ' + port
// : 'Port ' + port;
//
// switch (error.code) {
// case 'EACCES':
// console.error(bind + ' requires elevated privileges');
// process.exit(1);
// break;
// case 'EADDRINUSE':
// console.error(bind + ' is already in use');
// process.exit(1);
// break;
// default:
// throw error;
// }
// };
const port = normalizePort(process.env.PORT);
const AppName = pkg.name;
// not working with ApolloServer
// app.on('error', onError);
// Propagate "404 - not found" error
// not working with ApolloServer
// app.use(fnErr404);
apolloServer.start()
.then((res, req, next) => {
apolloServer.applyMiddleware({ app, path: '/graphql' });
app.listen({ port }, () => {
logger.debug(`Application: ${AppName} v.${pkg.version} - [BACKEND]`);
if (config.env === 'development') {
logger.info(`Server listening on http://localhost:${port}`);
} else {
logger.info(`Server listening on port ${port}`);
}
});
})
.catch((e) => {
logger.error(e.message);
});
// not working with ApolloServer
// General error handler
// app.use(function (err, req, res) {
// const status = err.status || httpStatus.INTERNAL_SERVER_ERROR;
// const accept = req.get('Accept') || '';
// const msg = err.message || httpStatus.getStatusText(status);
//
// // Log error
// switch (status) {
// case httpStatus.NOT_FOUND:
// logger.debug(status, req.url);
// break;
//
// default:
// logger.error(status, err.stack);
// break;
// }
//
// res.status(status);
//
// if (req.xhr || accept.indexOf('text/html') === -1) {
// res.end();
// } else {
// // Send HTML error page
// res.render('error', {
// status: status,
// message: msg,
// error: (app.get('env') === 'development') ? err.stack : ''
// });
// }
// });
My Quetsion now is, what must be done to get the error handling also working (marked with “not working with ApolloServer” → “General error handler”, “Propagate “404 - not found” error” and the “app.on(‘error’, onError)”)?
I can call the Api Routes, I also can serve to the static route, but if I uncomment the different error handling, the standard “/graphql” route is returning an error like:
Error: Not Found
at fnErr404 (C:\Users\xxx\__Development\graphql\server.js:29:15)
at Layer.handle [as handle_request] (C:\Users\xxx\__Development\graphql\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\xxx\__Development\graphql\node_modules\express\lib\router\index.js:323:13)
at C:\Users\xxx\__Development\graphql\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\xxx\__Development\graphql\node_modules\express\lib\router\index.js:341:12)
at next (C:\Users\xxx\__Development\graphql\node_modules\express\lib\router\index.js:275:10)
at SendStream.error (C:\Users\xxx\__Development\graphql\node_modules\serve-static\index.js:121:7)
at SendStream.emit (node:events:520:28)
at SendStream.error (C:\Users\xxx\__Development\graphql\node_modules\send\index.js:270:17)
at SendStream.onStatError (C:\Users\xxx\__Development\graphql\node_modules\send\index.js:421:12)
I also serached the internet, but a standard generated express app (with the CLI tool) and a implementation of the ApolloServer doesn’t seems to exist.
Hopefully my description of my question is not to confusing, and someone has a working tip or an example for me.
Thanks
Sascha