Why does express middleware override my api's response? - node.js

I am new to nodejs/express and have followed a blog article "Build Node.js RESTful APIs in 10 Minutes". It provided detailed steps to create simple REST apis. After finishing every code mentioned in the article, the app have not been working properly, it would just return
{
"url": "/transactions not found"
}
I found that the culprit was in the last part of the article, which told me to add this line to server.js:
Having done all these, what happens if we entered a wrong route? say
you entered 'http://localhost:3000/task', It responds with a message
“Cannot GET /task”. Let’s add express middleware which could be used
to return more interactive messages.
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
It seems to hardcode a HTTP status code of 404 no matter what does my api returns. After removing this line, the app return meaningful response.
Here is my server.js:
var express = require('express'),
app = express(),
port = process.env.PORT || 3000,
mongoose = require('mongoose'),
Transaction = require('./api/models/transactionModel'), //created model loading here
bodyParser = require('body-parser');
// mongoose instance connection url connection
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/transactionDb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
var routes = require('./api/routes/transactionRoutes'); //importing route
routes(app); //register the route
app.listen(port);
console.log('Transaction List RESTful API server started on: ' + port);
And the controller:
'use strict';
var mongoose = require('mongoose'),
Transaction = mongoose.model('Transactions');
exports.list_all_transactions = function (req, res) {
Transaction.find({}, function (err, transaction) {
if (err)
res.send(err);
res.json(transaction);
});
};
exports.create_a_transaction = function (req, res) {
var new_transaction = new Transaction(req.body);
new_transaction.save(function (err, transaction) {
if (err)
res.send('Error creating a new transaction!');
res.json(transaction);
});
};

it wasn't override your response, just because it returned in the middle before touch your api. The flow of request is running from top to bottom, example in your code above:
[coming request] --> bodyParser --> bodyParser --> 404 handler (returned here) -x-> api (cannot reach).
Just use() 404 middleware to the bottom and everything works fine.
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/transactionDb');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var routes = require('./api/routes/transactionRoutes'); //importing route
routes(app); //register the route
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});

I suspect your
app.use(function(req, res) {
res.status(404).send({url: req.originalUrl + ' not found'})
});
should be lower: the server is finding that piece of code first, while the actual routes are loaded later.
app.use means that it always executes that code, so it handles every request by sending a 404 error and saying it can't find the URL.
Put that code under all of the other routes (right above app.listen(port)) and it should work!

Related

Ionic/Angular not connecting properly to nodeJS (routes work perfectly in postman

I am able to run the GET & POST requests using POSTMAN, and it works. I cannot figure out where I'm going wrong in my app. My GET request to the same address works just fine.
Ex., In my service:
createOne(route, document) {
console.log(`create new ${route}`, document);
console.log(`http://localhost:8080/api/${route}`);
return this.http.post(`http://localhost:8080/api/${route}`, document);
}
This logs in the console as:
Unfortunately, it doesn't log a thing on the nodeJS server, so I'm sure I made a mistake somewhere in the server.js file - but can't figure out where!
POST request via postman to http://localhost:8080/api/appts with this for raw JSON body:
{
"title": "test from postman",
"description": "test description",
"startTime": "2020-08-04T17:40:45.521-04:00",
"endTime": "2020-08-04T20:10-04:00",
"allDay": false
}
My server.js file:
//1. require express and call it as a function
require('./api/data/db.js');
const cron = require('node-cron');
var express = require('express');
console.log(process.env.PORT);
var app = express();
var cors = require('cors');
var path = require('path');
var bodyParser = require('body-parser');
var routes = require('./api/routes');
var json2xls = require('json2xls');
//PORT SETUP
if (process.env.PORT) {
app.use(cors());
app.set('port', process.env.PORT || 8080);
} else {
app.set('port', 8080);
}
// MIDDLEWARE
app.use(function (req, res, next) {
console.log(req.method, req.url);
next();
});
app.use(json2xls.middleware);
// ROUTING
app.use(express.static(path.join(__dirname, 'app/www'))); //setup primary route request folder
app.use('/node_modules', express.static(path.join(__dirname, 'node_modules')));
app.use(bodyParser.urlencoded({ extended: true })); //only get strings and arrays from form when false
app.use(bodyParser.json()); // tell backend to understand json data
app.use('/api', routes);
// LOAD THE SINGLE PAGE FOR IONIC
app.get('*', function (req, res) {
res.sendFile('/app/www/index.html', { root: __dirname });
});
// START SERVER LISTENING
var server = app.listen(app.get('port'), function () {
var port = server.address().port; // return the port for the server listening
console.log('RayWood API running on port ' + port); //confirm app running
});
My File Tree is setup as follows:
Seeing how the nodeJS server doesn't log the URL or REQUEST, I think the problem is in my server.js file - but I still don't know what I did wrong. Please help!
You are not subscribing to Observable .If you are not familiar with Observable You can convert it to Promise please use below sample implemenation
createOne(route, document) {
console.log(`create new ${route}`, document);
console.log(`http://localhost:8080/api/${route}`);
return new Promise((resolve, reject) => {
this.http.post(`http://localhost:8080/api/${route}`,document).subscribe((resp)=>{
console.log(resp);//This is the response from Node API
resolve(resp);
},(err)=>{
reject(err)
});
});
}

React axios calls to Express API in Heroku deployment

I have a React todo app I built using create-react-app and I built a simple express server to query mongoDB to get all the appointment objects. It works just as expected when I am running it on my machine. The front end spins up on localhost:3000 and the server on localhost:3001. I use axios to make a get request to localhost:3000/api/appointments to load all the appointments into the App.js state. I uploaded it to Heroku and I got a CORS error on the request. After that, I tried to just use the route 'api/appointments' in the request and every permutation of that I can come up with which all respond with 404 errors.
Where does the node.env variable spin up the server on Heroku? And how do I call it fromm a React app with axios?
Same question in a different context if it helps:
When I run the app on my machine and access it with Postman, I can GET localhost:3001/api/appointmentsand it returns an array of JSON objects from the database just as I would expect. When I deploy to Heroku GET https://appointment-ledger-map.herokuapp.com/api/appointments returns all the markup for index.html. I assume this means that the api server is up and running because it responds but why is it not responding with the array of JSON objects as expected?
// server.js
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var Appointment = require('./model/appointments');
//and create our instances
var app = express();
var router = express.Router();
//set our port to either a predetermined port number if you have set
//it up, or 3001
var nodeEnv = process.env.NODE_ENV || 'development';
var port = process.env.PORT || 3001;
var host = process.env.HOST || '0.0.0.0';
//db config
mongoose.connect('mongodb://josh11:josh11#ds133162.mlab.com:33162/heroku_tl016m5d');
//now we should configure the API to use bodyParser and look for
//JSON data in the request body
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set
//our headers to allow CORS with middleware like so:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
//and remove cacheing so we get the most recent appointments
res.setHeader('Cache-Control', 'no-cache');
next();
});
//now we can set the route path & initialize the API
router.get('/', function(req, res) {
res.send({ message: 'API Initialized!'});
console.log('Api initialized');
});
//Use our router configuration when we call /api
app.use('/api', router);
//starts the server and listens for requests
app.listen(port, host, function() {
console.log(`api running on port ${port}`);
});
//adding the /appointments route to our /api router
router.route('/api/appointments')
//retrieve all appointments from the database
.get(function(req, res) {
//looks at our Appointment Schema
Appointment.find(function(err, appointments) {
if (err)
res.send(err);
//responds with a json object of our database appointments.
res.send(appointments)
});
console.log(appointments);
})
//post new appointment to the database
.post(function(req, res) {
var appointment = new Appointment();
//body parser lets us use the req.body
appointment.appointmentTitle = req.body.appointmentTitle;
appointment.appointmentDate = req.body.appointmentDate;
appointment.appointmentTime = req.body.appointmentTime;
appointment.appointmentDescription = req.body.appointmentDescription;
appointment.appointmentDestination = req.body.appointmentDestination;
appointment.appointmentOrigin = req.body.appointmentOrigin;
appointment.travelMode = req.body.travelMode;
appointment.save(function(err) {
if (err)
res.send(err);
res.send({ message: 'Appointment successfully added!' });
});
});
// App.js
loadAppointments() {
axios.get('/api/appointments')
.then(res => {
this.setState({
appointments: res.data,
filteredAppointments: res.data
});
})
}
npm install cors --save
then
var cors = require('cors');
finally
mongoose.connect('mongodb://josh11:josh11#ds133162.mlab.com:33162/heroku_tl016m5d');
//now we should configure the API to use bodyParser and look for
//JSON data in the request body
app.use(cors()); **//Must be before BodyParser**
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set
//our headers to allow CORS with middleware like so:
Re-deploy it and voila :)
Hope it helped you

Express finalhandler cannot 404 after headers sent

I have an express app and i have added new route:
this is the route:
var router = require('express').Router();
router.post('/',function (req, res, next) {
res.send("Ok");
});
module.exports = router;
now on every request that i make to this post route im getting at the express log:
finalhandler cannot 404 after headers sent
When making calls to DB the finalhandler does send 404 for every requst,
so im guessing that there is some kind of race with my functions and the finalhandler
anyone have anyidea?
UPDATE:
This is the index.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var expressValidator = require('express-validator');
var _ = require('underscore');
var stringUtils = require("underscore.string");
var mongoose = require('mongoose');
mongoose.connect(config.mongoUrl);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
var middleware = require('./middleware/authentication-middleware');
app.use(middleware.allowCrossDomains);
app.all('*', loginMiddlewareSkip);
var skipAuthPaths = ['/auth/fb', '/auth/login', '/auth/signup', '/auth/forgot', '/auth/reset'];
function loginMiddlewareSkip(req, res, next) {
if (stringUtils.startsWith(req.path, "/auth") || req.path == '/status'){
return next();
}
middleware.ensureAuthenticated(req,res,next);
next();
}
app.use('/passport', require('./routes/passport'));
app.use('/auth', require('./routes/authenticate'));
app.listen(3000, function() {
console.log('Express server listening on port ' + 3000);
});
The file above is the routes/passport, and the auth file is working fine
Ok the problem was with one of my middle wares:
in my loginMiddlewareSkip function i was calling
middleware.ensureAuthenticated(req,res,next) if the path need an authentication, inside that function i was calling next() if authentication is successfull and as you can see i was calling next() again after calling the ensureAuthenticated function.
removing the next() from loginMiddlewareSkip solved the problem

post using restler and node.js is not returning

I am trying to post using restler and return the response to client but response never returns .Below is code I am using and response is just hanging
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var rest = require('restler');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = 3001; // can also get it from process.env.PORT
var router = express.Router();
//this is like interceptor for every route to validate all requests, logging for analytics
router.use(function (req, res, next) {
console.log('route intercepted');
next(); // make sure we go to the next routes and don't stop here
});
router.get('/', function(req, res) {
res.json({ message: "welcome to restful node proxy layer to business processes" });
});
router.route('/someroute').post(function(req, res) {
rest.postJson('http://localhost/api/sg', req.body).on('complete', function(data, response) {
console.log(response);
}
).on('error', function(data, response) {
console.log('error');
});
});
app.use('/api', router); //all routes are prefixed with /api
app.listen(port);
console.log("server is running magic happens from here");

Node.js TypeError: Bear is not a function

I am trying to learn node.js from this tutorial: https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4
When I get to the Creating a Bear POST /api/bears section I get the following error from postman
It says bear is not a function and when I instantiate it var bear = new Bear(); is when I get the error.
Here is my bear.js
// app/models/bear.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BearSchema = new Schema({
name: String
});
module.exports = mongoose.model('Bear', BearSchema);
And here is my server.js
// server.js
// BASE SETUP
// =============================================================================
// call the packages we need
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
mongoose.connect('mongodb://node:node#novus.modulusmongo.net:27017/Iganiq8o'); // connect to our database
var Bear = require('./app/models/bear');
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set our port
// ROUTES FOR OUR API
// =============================================================================
var router = express.Router(); // get an instance of the express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
next(); // make sure we go to the next routes and don't stop here
});
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
// <-- route middleware and first route are here
// more routes for our API will happen here
// on routes that end in /bears
// ----------------------------------------------------
router.route('/bears')
// create a bear (accessed at POST http://localhost:8080/api/bears)
.post(function(req, res) {
var bear = new Bear(); // create a new instance of the Bear model
bear.name = req.body.name; // set the bears name (comes from the request)
// save the bear and check for errors
bear.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Bear created!' });
});
});
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
What can I do to make bear a function?
Sorry, i can't comment.
Try this things:
1.Use local mongodb database and set connection string here to yours:
mongoose.connect('mongodb://node:node#novus.modulusmongo.net:27017/Iganiq8o');
2.Set body parameter in Postman, not header.

Resources