There are obviously duplicate questions but the answers didn't help me. Either there is something fundamental that I just don't understand yet as a beginner in nodeJS and Express or something weird is happening.
I have two Express routes, the first one works perfectly fine. But as soon as I started working on the second one I immediately encountered the problem when trying to use 'res' to send back a HTTP status code.
server.js (with everything unrelated redacted):
const express = require('express')
const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session)
const db = require('./database')
const route1 = require('./routes/route1')
const route2 = require('./routes/route2')
const sessionStore = new MySQLStore({}, db)
const app = express()
app.use(express.json())
app.use(session({
// session settings
}))
// Routes
app.use('/api/route1', route1)
app.use('/api/route2', route2)
app.listen(process.env.PORT || 8000)
route1.js (with everything unrelated redacted):
const express = require('express')
const db = require('../database')
const router = express.Router()
// Middleware
function validateData(req, res, next) {...}
async function validateUser(req, res, next) {...}
// POST data to db
router.post('/', validateData, validateUser, async (req, res) => {
try {
const results = await db.query(
// Query the database
)
} catch(err) {
// Handle error
}
res.status(200).end()
})
module.exports = router
route2.js - where the error happens (with everything unrelated redacted):
const express = require('express')
const db = require('../database')
const router = express.Router()
router.get('/', (req, res) => {
res.statusCode(200).end() // TypeError: res.statusCode is not a function
})
module.exports = router
It says it correctly.
res.statusCode is not a function, it is Node.js native variable: https://nodejs.org/api/http.html#responsestatuscode
Express have function res.status(statusCode), i.e. res.status(200);: https://expressjs.com/en/api.html#res.status
I have got a problem with Express, I am trying to use the app.post() function but it's not working and I don't know why...
Even though I have included the bodyParser()...
It returns 404 page not found error
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var router = express.Router();
router.post("/hello",(req, res) => {
res.send('POST CALL');
});
/* GET home page. */
router.get('/', function(req, res, next) {
MongoClient.connect('mongodb://localhost:27017/nicky', function (err, client) {
if (err) throw err
var db = client.db('nicky')
db.collection('student').find().toArray(function (err, result) {
if (err) throw err
res.send(JSON.stringify(result));
})
})
});
module.exports = router;
GET is working properly, but POST is not.
I am not sure how rest of your code looks, but I have copied your provided snippet and it works this way:
express-post.js:
const express = require('express');
const router = express.Router();
// curl -X POST http://localhost:3000/bar/hello
router.post("/hello",(req, res) => {
res.send('It is POST');
});
// curl -X GET http://localhost:3000/bar/hi
router.get('/hi', function(req, res, next) {
res.send('It is GET');
});
module.exports = router;
express-post-server.js:
const express = require('express');
const bar = require('./express-post');
const app = express();
// curl -X GET http://localhost:3000/foo
app.get('/foo', function (req, res, next) {
res.send('This is foo GET!');
});
// register
app.use('/bar', bar);
app.listen(3000);
For complete running example clone node-cheat and run node express-post.
Maybe you haven't required and initialized body-parser!
Just confirm once if you have included this:
const bodyParser = require('body-parser');
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
May be you forgot to use
app.use('/',require('import route here'));
in main app.
I'm new to nodeJS and testing and I'd like to know how I can test my application routes properly. I've read some articles that uses supertest and chai-http to call the POST method but I believe this way would be more of an integration testing instead of unit testing my app.
I've read about Sinon but I'm having a hard time applying it on my code like I don't know what to stub, how I can manipulate the data from the request body so I can cover different branches of my conditional statements. I'm monitoring my code coverage with nyc so I'm also aiming to increase my unit test coverage.
I would appreciate it a lot if someone can guide me on this. Thanks in advance!
server.js
const express = require('express');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.listen(8080, function () {
logger.info('App is now running on port 8080');
});
app.use('/', require('./routes/generateURL.js'));
module.exports = app;
generateURL.js
const express = require('express');
const router = express.Router();
router.post('/generate-url', (req, res) => {
let result = {
status: false
};
const acctId = req.body.accountId;
const baseURL = 'http://somecompany.com/billing/';
const dateToday = new Date();
try {
if (accountId) {
result.status = true;
result.bill = baseURL + acctId + '/' + dateToday;
} else {
throw 'Missing accountId';
}
} catch(err){
console.log(err);
}
return res.send(result);
});
module.exports = router;
I've searched and tried other results, but none seem to render any results.
I'm trying to post data to the backend using postman as a test. The response is sending the 'success' message, but req.body returns an empty array every time I try. I'm using a node backend, with express and I'm trying to use routes. I've had success before, but for some reason I can't get it this time and my old code doesn't seem to work for this one. If I just log req, rather than req.body, I can see that the body is empty, the params are empty, but the url includes the params. I can post it, but it's rather long and I don't know if it's useful.
Here's the url I'm trying to hit: localhost:3000/?testParam=test&test=boop
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/blogTest', { useNewUrlParser: true });
mongoose.Promise = global.Promise;
const postsRoute = require('./routes/post');
app.use(postsRoute);
module.exports = app;
post.js
const express = require('express');
const router = express.Router();
const postModel = require('../models/post'); //not using this yet
router.get("/", function(req, res){
console.log("Getting Posts...");
postModel.find({}, function(err, posts){
if(err){
res.send("{'status': 'error', 'response': "+err+"}");
}
else if(posts.length < 1){
res.send("{'status': 'null', 'response': {}}");
}
else{
res.send("{'status': 'success', 'response': "+posts+"}");
}
});
});
router.post("/", function(req, res){
console.log(req.body);
res.send('success');
});
module.exports = router;
I'm expecting the console to log {'testParam': 'test','test':'boop'}
also, I've tried parsing req.body as json and stringifying it, but it causes the server to crash.
I think you are confused about http methods and how they work.
req.body is the POST request body, it is the data passed by the client when he sends a POST request to your api endpoint. If you are not sending any data in your POST request, then req.body will be empty.
In your example, to get the data from a request like localhost:3000/?testParam=test&test=boop you would need to look in req.params instead of req.body.
You need to try accessing the params variable of the request by code, trying to go through a log to find params might not be accurate therefore try
router.post("/", function(req, res){
console.log(req.params);
res.send('success');
});
This question already has answers here:
How to separate routes on Node.js and Express 4?
(9 answers)
Closed 1 year ago.
In my NodeJS express application I have app.js that has a few common routes. Then in a wf.js file I would like to define a few more routes.
How can I get app.js to recognize other route handlers defined in wf.js file?
A simple require does not seem to work.
If you want to put the routes in a separate file, for example routes.js, you can create the routes.js file in this way:
module.exports = function(app){
app.get('/login', function(req, res){
res.render('login', {
title: 'Express Login'
});
});
//other routes..
}
And then you can require it from app.js passing the app object in this way:
require('./routes')(app);
Have a look at these examples: https://github.com/visionmedia/express/tree/master/examples/route-separation
In Express 4.x you can get an instance of the router object and import another file that contains more routes. You can even do this recursively so your routes import other routes allowing you to create easy-to-maintain URL paths.
For example, if I have a separate route file for my /tests endpoint already and want to add a new set of routes for /tests/automated I may want to break these /automated routes out into a another file to keep my /test file small and easy to manage. It also lets you logically group routes together by URL path which can be really convenient.
Contents of ./app.js:
var express = require('express'),
app = express();
var testRoutes = require('./routes/tests');
// Import my test routes into the path '/test'
app.use('/tests', testRoutes);
Contents of ./routes/tests.js:
var express = require('express'),
router = express.Router();
var automatedRoutes = require('./testRoutes/automated');
router
// Add a binding to handle '/tests'
.get('/', function(){
// render the /tests view
})
// Import my automated routes into the path '/tests/automated'
// This works because we're already within the '/tests' route
// so we're simply appending more routes to the '/tests' endpoint
.use('/automated', automatedRoutes);
module.exports = router;
Contents of ./routes/testRoutes/automated.js:
var express = require('express'),
router = express.Router();
router
// Add a binding for '/tests/automated/'
.get('/', function(){
// render the /tests/automated view
})
module.exports = router;
Building on #ShadowCloud 's example I was able to dynamically include all routes in a sub directory.
routes/index.js
var fs = require('fs');
module.exports = function(app){
fs.readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
Then placing route files in the routes directory like so:
routes/test1.js
module.exports = function(app){
app.get('/test1/', function(req, res){
//...
});
//other routes..
}
Repeating that for as many times as I needed and then finally in app.js placing
require('./routes')(app);
If you're using express-4.x with TypeScript and ES6, this would be the best template to use:
src/api/login.ts
import express, { Router, Request, Response } from "express";
const router: Router = express.Router();
// POST /user/signin
router.post('/signin', async (req: Request, res: Response) => {
try {
res.send('OK');
} catch (e) {
res.status(500).send(e.toString());
}
});
export default router;
src/app.ts
import express, { Request, Response } from "express";
import compression from "compression"; // compresses requests
import expressValidator from "express-validator";
import bodyParser from "body-parser";
import login from './api/login';
const app = express();
app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.get('/public/hc', (req: Request, res: Response) => {
res.send('OK');
});
app.use('/user', login);
app.listen(8080, () => {
console.log("Press CTRL-C to stop\n");
});
Much cleaner than using var and module.exports.
Full recursive routing of all .js files inside /routes folder, put this in app.js.
// Initialize ALL routes including subfolders
var fs = require('fs');
var path = require('path');
function recursiveRoutes(folderName) {
fs.readdirSync(folderName).forEach(function(file) {
var fullName = path.join(folderName, file);
var stat = fs.lstatSync(fullName);
if (stat.isDirectory()) {
recursiveRoutes(fullName);
} else if (file.toLowerCase().indexOf('.js')) {
require('./' + fullName)(app);
console.log("require('" + fullName + "')");
}
});
}
recursiveRoutes('routes'); // Initialize it
in /routes you put whatevername.js and initialize your routes like this:
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('index', { title: 'index' });
});
app.get('/contactus', function(req, res) {
res.render('contactus', { title: 'contactus' });
});
}
And build yet more on the previous answer, this version of routes/index.js will ignore any files not ending in .js (and itself)
var fs = require('fs');
module.exports = function(app) {
fs.readdirSync(__dirname).forEach(function(file) {
if (file === "index.js" || file.substr(file.lastIndexOf('.') + 1) !== 'js')
return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
I am trying to update this answer with "express": "^4.16.3". This answer is similar to the one from ShortRound1911.
server.js:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const db = require('./src/config/db');
const routes = require('./src/routes');
const port = 3001;
const app = new express();
//...use body-parser
app.use(bodyParser.urlencoded({ extended: true }));
//...fire connection
mongoose.connect(db.url, (err, database) => {
if (err) return console.log(err);
//...fire the routes
app.use('/', routes);
app.listen(port, () => {
console.log('we are live on ' + port);
});
});
/src/routes/index.js:
const express = require('express');
const app = express();
const siswaRoute = require('./siswa_route');
app.get('/', (req, res) => {
res.json({item: 'Welcome ini separated page...'});
})
.use('/siswa', siswaRoute);
module.exports = app;
/src/routes/siswa_route.js:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({item: 'Siswa page...'});
});
module.exports = app;
If you want a separate .js file to better organize your routes, just create a variable in the app.js file pointing to its location in the filesystem:
var wf = require(./routes/wf);
then,
app.get('/wf', wf.foo );
where .foo is some function declared in your wf.js file. e.g
// wf.js file
exports.foo = function(req,res){
console.log(` request object is ${req}, response object is ${res} `);
}
One tweak to all of these answers:
var routes = fs.readdirSync('routes')
.filter(function(v){
return (/.js$/).test(v);
});
Just use a regex to filter via testing each file in the array. It is not recursive, but it will filter out folders that don't end in .js
I know this is an old question, but I was trying to figure out something like for myself and this is the place I ended up on, so I wanted to put my solution to a similar problem in case someone else has the same issues I'm having. There's a nice node module out there called consign that does a lot of the file system stuff that is seen here for you (ie - no readdirSync stuff). For example:
I have a restful API application I'm trying to build and I want to put all of the requests that go to '/api/*' to be authenticated and I want to store all of my routes that go in api into their own directory (let's just call it 'api'). In the main part of the app:
app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));
Inside of the routes directory, I have a directory called "api" and a file called api.js. In api.js, I simply have:
var express = require('express');
var router = express.Router();
var consign = require('consign');
// get all routes inside the api directory and attach them to the api router
// all of these routes should be behind authorization
consign({cwd: 'routes'})
.include('api')
.into(router);
module.exports = router;
Everything worked as expected. Hope this helps someone.
index.js
const express = require("express");
const app = express();
const http = require('http');
const server = http.createServer(app).listen(3000);
const router = (global.router = (express.Router()));
app.use('/books', require('./routes/books'))
app.use('/users', require('./routes/users'))
app.use(router);
routes/users.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'John Smith'})
}
module.exports = router
routes/books.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'Dreams from My Father by Barack Obama'})
}
module.exports = router
if you have your server running local (http://localhost:3000) then
// Users
curl --request GET 'localhost:3000/users' => {name: 'John Smith'}
// Books
curl --request GET 'localhost:3000/books' => {name: 'Dreams from My Father by Barack Obama'}
I wrote a small plugin for doing this! got sick of writing the same code over and over.
https://www.npmjs.com/package/js-file-req
Hope it helps.
you can put all route functions in other files(modules) , and link it to the main server file.
in the main express file, add a function that will link the module to the server:
function link_routes(app, route_collection){
route_collection['get'].forEach(route => app.get(route.path, route.func));
route_collection['post'].forEach(route => app.post(route.path, route.func));
route_collection['delete'].forEach(route => app.delete(route.path, route.func));
route_collection['put'].forEach(route => app.put(route.path, route.func));
}
and call that function for each route model:
link_routes(app, require('./login.js'))
in the module files(for example - login.js file), define the functions as usual:
const login_screen = (req, res) => {
res.sendFile(`${__dirname}/pages/login.html`);
};
const forgot_password = (req, res) => {
console.log('we will reset the password here')
}
and export it with the request method as a key and the value is an array of objects, each with path and function keys.
module.exports = {
get: [{path:'/',func:login_screen}, {...} ],
post: [{path:'/login:forgotPassword', func:forgot_password}]
};