errorMiddleware not working as expected in express - node.js

My errorHandler middleware is not showing up the response.
Instead of giving the error in json format as I have coded, it still shows the error in html format. Where did i go wrong?
app.js
import express from "express";
import dotenv from "dotenv";
import connectDB from "./config/db.js";
import colors from "colors";
import productRoutes from "./routes/productRoutes.js";
import errorHandler from "./middlewares/errorMiddleware.js";
dotenv.config();
// Connecting to MongoDB
connectDB();
// Express specific
const app = express();
// Middlewares
app.use(errorHandler);
app.use("/api/products", productRoutes);
app.use("/api/products/:id", productRoutes);
const PORT = process.env.PORT || 5000;
app.listen(
PORT,
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
);
errorMiddleware.js
const errorHandler = (err, req, res, next) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode; //we sometimes get 200 code (ok) even if its error. 500 means server error
res.status(statusCode);
res.json({
message: err.message,
stack: process.env.NODE_ENV === "production" ? null : err.stack,
});
};
export default errorHandler;
Output:
expected Output:
{
message: ...
stack: ...
}

You define error-handling middleware last, after other app.use() and routes call
source
Here is the basic working example
import express from "express";
const app = express();
app.use('/api/products', (req, res) => {
throw new Error('Triggers an error');
});
// Do other routes here and keep error handling below.
app.use((err, req, res, next) => {
res.status(res.statusCode);
res.json({
message: err.message,
stack: process.env.NODE_ENV === "production" ? null : err.stack,
});
})
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server started on port ${PORT}`);
});
Your only mistake is defining the middleware order.

Related

MERN App - Error when hosting my app on heroku

different response result when I use localhost url or the heroku url
As you can see in the picture, in blue we succesfully have the result response. But not when hosted in heroku (green on picture).
Here is the response from api when I try to fetch:
response
But those params are set in .env file (backend).
Can someone help me with this ? The cors is configured on the backend, so I don't know what I can do more...
server.js:
const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const cors = require("cors");
const dotenv = require("dotenv");
const colors = require("colors");
const dbConnect = require("./database/dbConnect");
dotenv.config();
// *** ROUTES IMPORT ***
const usersRoutes = require("./routes/users-routes");
const ovhRoutes = require("./routes/ovh-routes");
const renewDomainsRoutes = require("./routes/renew-domain-routes");
const meRoutes = require("./routes/me-routes");
const internetBsRoutes = require("./routes/internetbs-routes");
const domainsRoutes = require("./routes/domains-routes");
const orderRoutes = require("./routes/order-routes");
// execute database connection
dbConnect();
const app = express();
app.use(bodyParser.json());
app.use(cors());
/**
* ROUTES
*/
app.use("/api/users", usersRoutes); // => /api/users/...
app.use("/api/ovh", ovhRoutes); // => /api/ovh/...
app.use("/api/renew", renewDomainsRoutes);
app.use("/api/me", meRoutes);
app.use("/api/internetbs", internetBsRoutes);
app.use("/api/domains", domainsRoutes);
app.use("/api/order", orderRoutes);
app.use((req, res, next) => {
throw new HttpError("Could not find this route.", 404);
});
app.use((error, req, res, next) => {
if (res.headerSent) {
return next(error);
}
res.status(error.code || 500);
res.json({ message: error.message || "An unknown error occurred!" });
});
/**
* DEPLOYMENT
*/
if (process.env.NODE_ENV === "production") {
// Step 1:
app.use(express.static(path.resolve(__dirname, "./client/build")));
// Step 2:
app.get("*", function (request, response) {
response.sendFile(path.resolve(__dirname, "./client/build", "index.html"));
});
}
app.listen(
process.env.PORT || 5000,
console.log(`Server is running on port ${process.env.PORT}`.blue.bold)
);
The data are fetched from internet.bs API.
Thanks all!

nodejs custom error response does not take code error argument

I'm workin with a custom error response that I found in a tutorial. it's working correctly in all the node server, but in a specifies line it doesn't take the argument that specified the error code. It should return a 401 error but instead is returning me a 500 error code.
errorResponse.js
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
module.exports = ErrorResponse;
The next is the porcion of code that doesn't working well.
auth.js
return next(new ErrorResponse('Unauthorized', 401))
If I use this aproach the error code is the correct.
return res.status(401).json('Unauthorized')
Edited and share server.js
require('dotenv').config({path: './config.env'});
const express = require('express');
const connectDB = require('./config/db');
const errorHandler = require('./middlewares/error');
connectDB();
const app = express();
app.use(express.json());
app.use('/api/auth', require('./routes/auth'));
app.use('/api/private', require('./routes/private'));
const PORT = process.env.PORT || 5000;
const server = app.listen(PORT, () => console.log('server on port', PORT));
process.on("unhandledRejection", (err, promise) => {
console.log(`logged Error: ${err}`)
server.close(() => process.exit(1))
});
app.use(errorHandler);
error.js
const errorHandler = (err, req, res, next) =>{
let error = { ...err };
error.message = err.message
if(err.code === 11000) {
const message = `Error de duplicaciĆ³n`;
error = new ErrorResponse(message, 400)
}
if(err.name === "ValidationError") {
const message = Object.values(err.errors).map((val) => val.message);
err = new ErrorResponse(message, 400)
}
res.status(error.status || 500 ).json({
succes: false,
error: error.message || "Error del servidor"
})
}

Getting 'port already in use error' when adding socket.io to express app - happens on any port I try

As stated in the title, I'm getting 'address already in use error' when trying to add socket.io to an existing express app.
It happens on every port so the only thing I can think of is it's trying to set port 8000 twice. I don't see where, however.
Here is the error in the console.
Here is my config.js
module.exports = {
PORT: process.env.PORT || 8000,
NODE_ENV: process.env.NODE_ENV || 'development',
DATABASE_URL: process.env.DATABASE_URL || 'postgresql://postgres#localhost/quik'
}
.env
NODE_ENV=development
PORT=8000
And here is my main express app. I've tried setting PORT from process.env and directly with '8000'.
require('dotenv').config()
const morgan = require('morgan')
const cors = require('cors')
const helmet = require('helmet')
const { NODE_ENV } = require('./config')
const userRouter = require('./user/user_router')
const pinsRouter = require('./pins/pins_router')
const chatRouter = require('./chat/chat_router')
const config = require('./config')
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
http.listen(config.PORT, function(){
console.log('listening on *:8000');
});
const morganOption = (NODE_ENV === 'production')
? 'tiny'
: 'common';
app.use(morgan(morganOption))
app.use(helmet())
app.use(cors())
app.use('/user_route', userRouter)
app.use('/pins_route', pinsRouter)
app.use('/chat_route', chatRouter)
app.get('/', (req, res) => {
res.send('Hello, world!')
})
app.use(function errorHandler(error, req, res, next) {
let response
if (NODE_ENV === 'production') {
response = { error: { message: 'server error' } }
} else {
console.error(error)
response = { message: error.message, error }
}
res.status(500).json(response)
})
module.exports = app
The stack trace in the error appears like you are calling app.listen() somewhere (probably from your server.js - line 13). You need to go find that code and remove it. You only want to attempt to start your same server once and your http.listen() is already starting it once.

Can't use axios to get/post data from/to localhost server in android 7.0 device - React Native app

I use Axios in my react native app. I use Mobiistar Zumbo J2 with Expo to test but I get err: Network Error. I also set CORS for my node server but it still doesn't work. I test with Postman it work normally. Here is my code:
server.js
const express = require("express");
const path = require("path");
const bodyParser = require("body-parser");
const index = require("./routes/index");
const bookings = require("./routes/bookings");
const cors = require('cors'); // Yep, you need to install this
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.listen(port, () => {
console.log('Server is running on port', port);
});
app.set("views", path.join(__dirname, "views"));
app.set("view engine", 'ejs');
app.engine("html", require("ejs").renderFile);
//Body parser MW
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
//Routes
app.use("/", index);
app.use("/api", bookings);
bookings.js
const express = require("express");
const router = express.Router();
const mongojs = require("mongojs");
const db = mongojs("mongodb://<username>:<password>#ds139614.mlab.com:39614/booking-car-app", ["bookings"]);
router.get("/bookings", (req, res, next) => {
db.bookings.find((err, data) => {
if (err) {
res.send(err);
}
res.json(data);
});
});
router.post("/bookings", (req, res, next) => {
const booking = req.body;
if (!booking.userName) {
res.status(400);
res.json({err: "Bad data"});
} else {
db.bookings.save(booking, (err, savedBooking) => {
if (err) {
res.send(err);
}
res.json(savedBooking);
})
}
})
module.exports = router;
using Axios to get data from server
axios.get("http://127.0.0.1:3000/api/bookings/")
.then(res => {
console.log("Get booking info: ", res);
alert(res);
})
.catch(err => console.log(err))
Error:
Network Error
Stack trace:
node_modules\axios\lib\core\createError.js:16:24 in createError
node_modules\axios\lib\adapters\xhr.js:87:25 in handleError
node_modules\event-target-shim\lib\event-target.js:172:43 in dispatchEvent
node_modules\react-native\Libraries\Network\XMLHttpRequest.js:578:29 in setReadyState
node_modules\react-native\Libraries\Network\XMLHttpRequest.js:392:25 in __didCompleteResponse
node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:191:12 in emit
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:349:47 in __callFunction
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:106:26 in <unknown>
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:297:10 in __guard
node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:105:17 in callFunctionReturnFlushedQueue
...
Please help me.
Thank you very much
Android uses a special type of IP address 10.0.2.2
axios.get("http://10.0.2.2:3000//api/bookings/")
.then(res => {
console.log("Get booking info: ", res);
alert(res);
})
.catch(err => console.log(err))

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('--------------------------------------------------------------------------');
};

Resources