Why is my route not found if I use /:var/action - node.js

My app.js has the following:
const express = require('express');
const app = express();
const userRoutes = require('./api/routes/users');
// middleware - takes info passed in through the body
app.use(express.urlencoded({extended: false}));
app.use(express.json());
// middleware - adds headers to allow CORS.
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
if(req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, DELETE, GET');
res.status(200).json({});
}
next();
});
// middleware - filter all requests for users to the userRoutes
app.use('/api/v1/users', userRoutes);
// middleware - catch any requests that aren't caught by previous filters
app.use((req, res, next) => {
const error = new Error('No route found');
error.status = 404;
next(error);
});
// middleware - catch any errors that happen other places in the application (DB, etc.)
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: { message: error.message }
});
});
module.exports = app;
and my userRoutes looks like this:
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const gtrController = require('../controllers/gtrController');
const DAL = require('../DAL/dal');
router.get('/:userName', (req, res, next) => {
userController.getUser(req.params.userName, DAL.findOne, gtrController.getUser)
.then((result) => {
res.status(200).json(result);
})
.catch((error) => {
console.log(error);
res.status(500).json({ Error: { message: error }})
});
});
router.get('/:userName/games', (req, res, next) => {
userController.getUserStuff(req.params.userName, () => {}, gtrController.getUserStuff)
.then((result) => {
res.status(200).json(result);
})
.catch((error) => {
console.log(error);
res.status(500).json({ Error: { message: error }})
});
});module.exports = router;
If I check / and /username in Postman, I get 200's and all is right. However, when I try /username/games, I get a 404. I'm not sure why it's not hitting my userRoutes. I'm assuming it's my app.use, but I'm not finding any relevant documentation.
Thanks a bunch.

Figured it out, I think. My router.get('/:userName/games) should be router.get('/:userName\/games')

Related

Express make try/catch block into middleware to avoid duplication

Im writing my expressJs application, and Im finding in my routes controller the same duplicated code for catching exception, I was wondering how to avoid this.
I have checked this thread, but I get this error "Cannot read property 'catch' of undefined" : Express Try and Catch in Form of middleware
this is my route.js
const express = require("express");
const createHttpError = require("http-errors");
const Validator = require("../middlewares/Validator");
const TaskNotFoundException = require("../services/TaskNotFoundException");
const TaskService = require("../services/TaskService");
router.get("/tasks", async (req, res, next) => {
try {
const data = await TaskService.getTasks();
res.send({ code: 200, message: "Success", data });
} catch (error) {
next(createHttpError(500));
}
});
router.get("/task/:id", async (req, res, next) => {
const { id } = req.params;
try {
const data = await TaskService.getTask(id);
res.send({ code: 200, message: "Success", data });
} catch (error) {
if (error instanceof TaskNotFoundException) {
next(createHttpError(404));
} else {
next(createHttpError(500));
}
}
});
and the list goes on
as you see in all my routes I have a try catch block with the possible errors (either only a 500, or a 500/404). And I would like to avoid this repetition.
this is my app.js
const express = require("express");
const bodyParser = require("body-parser");
const createHttpError = require("http-errors");
const api = require("./routes/api");
const app = express();
app.use(express.json());
app.use(bodyParser.json());
app.use("/api", api);
// Catch HTTP 404
app.use((req, res, next) => {
next(createHttpError(404));
});
// Error Handler
app.use((err, req, res, next) => {
res.status(err.status || 500);
res.json({
error: {
status: err.status || 500,
message: err.message,
},
});
});
module.exports = app;
Like I said, it works perfectly now, I would just like to try to avoid the try catch code duplication, and Ive checked the other questions in Stackoverflow but havent helped. The solution ive linked returns a 500 with this catch undefined message (which is not what I want) and on other routes that also have a 404 it just doesnt work.
Thanks a lot!
Update:
I followed Heikos advice but still not working
api.js
const express = require("express");
const createHttpError = require("http-errors");
const Validator = require("../middlewares/Validator");
const TaskNotFoundException = require("../services/TaskNotFoundException");
const TaskService = require("../services/TaskService");
const router = express.Router();
router.get("/tasks", async (req, res, next) => {
const data = await TaskService.getTasks();
res.send({ code: 200, message: "Success", data });
});
app.js
const express = require("express");
const bodyParser = require("body-parser");
const createHttpError = require("http-errors");
const api = require("./routes/api");
const app = express();
app.use(express.json());
app.use(bodyParser.json());
app.use("/api", api);
function catchAsyncErrors(middleware) {
return async function(req, res, next) {
try {
await middleware(req, res, next);
} catch(err) {
next(err);
}
};
}
// Catch HTTP 404
app.use(catchAsyncErrors((req, res, next) => {
next(createHttpError(404));
}));
// Error Handler
app.use(catchAsyncErrors((err, req, res, next) => {
res.status(err.status || 500);
res.json({
error: {
status: err.status || 500,
message: err.message,
},
});
}));
module.exports = app;
If the code inside your async middleware functions contains an await, you must also wrap it in a try-catch block, otherwise a rejected promise will be unhandled. For example:
app.use(async function(req, res, next) {
try {
await Promise.reject("error");
} catch(err) {
next(err);
}
});
propagates the error to the error handler, but without the try-catch block it leads to an "UnhandledPromiseRejection".
You can save some typing if you wrap your middleware into a catchAsyncErrors function:
function catchAsyncErrors(middleware) {
return async function(req, res, next) {
try {
await middleware(req, res, next);
} catch(err) {
next(err);
}
};
}
router.get("/tasks", catchAsyncErrors(async (req, res, next) => {
const data = await TaskService.getTasks();
res.send({ code: 200, message: "Success", data });
}));

Postman connection issue (NodeJS + MongoDB Atlas)

I have been googling, searching on stack and been trying to solve this for a while now.
None of the posted solutions seem to help.
Server runs smoothly in VSC (if I input wrong pass, it gives authentication error.
Seemingly, it connects fine).
Tried with Compass and it connects fine there too.
Posting this in Postman [RAW > JSON/Application]:
{
"name": "Harry Potter",
"price": "12.99"
}
Returns this in VSC:
POST /products - - ms - -
And an error message in Postman: Error: read ECONNRESET
I am following a RESTful API series on youtube.
I am a bit confused as to where the problem lies then. Any ideas?
Any help would be greatly appreciated. Thanks in advance!
server.js
const http = require('http');
const app = require('./app');
const port = process.env.PORT || 3000;
const server = http.createServer(app);
server.listen(port);
app.js
const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
// Set route for product and order
const productRoutes = require('./api/routes/products');
const orderRoutes = require('./api/routes/orders');
mongoose.connect(
'mongodb://testDB:' +
process.env.MONGO_ATLAS_PW +
'#node-rest-shop-shard-00-00.e0tzo.mongodb.net:27017,node-rest-shop-shard-00-01.e0tzo.mongodb.net:27017,node-rest-shop-shard-00-02.e0tzo.mongodb.net:27017/test?ssl=true&replicaSet=atlas-be641c-shard-0&authSource=admin&retryWrites=true&w=majority',
{
useNewUrlParser: true,
useUnifiedTopology: true
}
);
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Header', 'Origin, X-Requested-Width, Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
});
// Routes which handles
app.use('/products', productRoutes);
app.use('/orders', orderRoutes);
app.use((req, res, next) => {
const error = new Error('Not found');
error.status = 404;
next(error);
})
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
});
module.exports = app;
models/product.js
const mongoose = require('mongoose');
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectID,
name: String,
price: Number
});
module.exports = mongoose.model('Product', productSchema);
routes/orders.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
res.status(200).json({
message: 'Orders were fetched'
});
});
router.post('/', (req, res, next) => {
const order = {
productId: req.body.productId,
quantity: req.body.quantity
};
res.status(201).json({
message: 'Order was created',
orders: order
});
});
router.get('/:orderId', (req, res, next) => {
res.status(200).json({
message: 'Order details',
orderId: req.params.orderId
});
});
router.delete('/:orderId', (req, res, next) => {
res.status(200).json({
message: 'Order deleted',
orderId: req.params.orderId
});
});
module.exports = router;
routes/products.js
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Product = require('../models/product');
router.get('/', (req, res, next) => {
res.status(200).json({
message: 'handling GET requests to /products'
});
});
router.post('/', (req, res, next) => {
const product = new Product({
_id: new mongoose.Types.ObjectId(),
name: req.body.name,
price: req.body.price
});
product.save().then(result => {
console.log(result);
})
.catch(err => console.log(err));
res.status(201).json({
message: 'handling POST requests to /products',
createProduct: product
});
});
router.get('/:productId', (req, res, next) => {
const id = req.params.productId;
if (id === 'special') {
res.status(200).json({
mesage: 'Special ID discovered',
id: id
});
} else {
res.status(200).json({
message: 'You passed an ID',
id: id
});
}
});
router.patch('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Updated product!'
});
});
router.delete('/:productId', (req, res, next) => {
res.status(200).json({
message: 'Deleted product!'
});
});
module.exports = router;
nodemon.json
{
"env": {
"MONGO_ATLAS_PW": "<user password here - removed for post>"
}
}

Backend Node routes not working after heroku deployment

I have recently deployed my node.js backend using Heroku but now it seems like my routes don't work anymore. It always goes through my error route to return "Could not find this route." This did not happen when I was using localhost whilst developing.
app.js:
const express = require('express');
const bodyParser = require('body-parser');
const HttpError = require('./models/httpError');
const questionRoutes = require('./routes/questionRoutes');
const app = express();
app.use(bodyParser.json());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
next();
});
app.use('/api/questions', questionRoutes);
app.use((req, res, next) => {
console.log(req.url);
const error = new HttpError('Could not find this route.', 404);
throw error;
});
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!' });
});
app.listen(process.env.PORT || 5000);
I am not using any environment variables. Here is the heroku link to my backend: https://mealoftheday.herokuapp.com/
Any help would be appreciated!
router.get('*', (request, response) => {
response.sendFile(path.join(__dirname, 'etsa2/build', 'index.html'));
});
Add this file to your routes my issue was solved hope yours too get solved

incomplete response received from application nodejs

I'm using nodejs on nginx server. Sometimes the node app is crashing and returning 'incomplete response received from application'. What is causing this problem?
const Express = require('express');
const BodyParser = require('body-parser');
const Request = require('request');
const Conf = require('./conf');
const {db} = require('./lib/database');
const app = Express();
app.use(BodyParser.json());
app.use(BodyParser.urlencoded({extended: false}));
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'POST');
if ('OPTIONS' == req.method) {
res.header('Access-Control-Allow-Methods', 'POST');
return res.sendStatus(200);
}
next();
});
app.post('/getProperty', (req, res) => {
const sql = "SELECT ('['||(st_asgeojson(geom)::json)||']')::json FROM spt.spt where id=" + req.body.id;
db.query(sql, (err, result) => {
if (err) res.status(err.code).json({code: err.code, message: err.message}).end();
(result.rows.length == 0) ? res.send([]) : res.send(result.rows[0].json);
})
});
app.post('/getAnalysis', (req, res) => {
const sql = "select value from test.test where id=" + req.body.id + " order by value asc";
db.query(sql, (err, result) => {
if (err) result.status(err.code).json({code: err.code, message: err.message}).end();
res.send(result.rows);
})
});
app.listen(3000);
If an error occurs, your code tries sending a response twice. You need to exit the function after sending the error response to the client, so either use return in your if or add an else below for the success response.
Sending multiple responses will dicsonnect the socket in express.

How to avoid internal server error without using try catch clause in node js?

Server.js file
var express = require('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var fs = require('fs');
var app = express();
var os = require('os');
//app.use(logger('dev'));
app.use(bodyParser.json());
app.all('/*', function (req, res, next) {
// CORS headers
res.header("Access-Control-Allow-Origin", "*"); // restrict it to the required domain
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
// Set custom headers for CORS
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
if (req.method == 'OPTIONS') {
res.status(200).end();
} else {
next();
}
});
// Auth Middleware - This will check if the token is valid
// Only the requests that start with /api/v1/* will be checked for the token.
// Any URL's that do not follow the below pattern should be avoided unless you
// are sure that authentication is not needed
//app.all('/api/v1/*', [require('./middlewares/validateRequest')]);
app.use('/', require('./routes')); // Write url in the routes.js file
app.use(function (err, req, res, next) {
if (!err) {
return next();
}
else {
return next();
}
});
//404 error handler
// If no route is matched by now, it must be a 404
app.use(function (req, res, next) {
var err = new Error('URL Not Found');
err.status = 404;
var date = new Date();
next(err);
});
// Start the server
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
console.log('Express server listening on port ' + server.address().port);
});
I have read to handle internal server error
Do like that. I even tried that too but it won't run as I wanted
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
console.log(err.message+' w');
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
How to avoid that so that the server won't shot down ?
Tried that link too https://expressjs.com/en/guide/error-handling.html , http://code.runnable.com/UTlPPF-f2W1TAAEU/error-handling-with-express-for-node-js
For express middleware error handling
Catch 404 and forward to error handler
app.use(function(req, res) {
res.status(404).send({
error: 'Not found'
});
});
if (app.get('env') === 'development') {
app.use(function(error, req, res, next) {
debug('http_status: %d, %s', error.status || 500, error.message);
next(error);
});
}
app.use(function(error, req, res) {
res.status(error.status || 500).send({
error: 'Internal server error'
});
});
Catch the uncaught errors that weren't wrapped in a domain or try catch statement
Note: Do not use this in modules, but only in applications, as otherwise, we could have multiple of these bound
process.on('exit', function(code) {
});
process.on('uncaughtException', function(err) {
console.log(err)
});
process.on('SIGINT', function() {
process.exit(0);
});

Resources