I had all my routes in server.js but I wanted to make it modular and put into a folder called routes. I created a file called apis.js in routes folder but as I did that I get TypeError: app.post is not a function
server.js:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: true});
app.use(express.static('public'));
var apis = require('./routes/apis');
app.use('/', apis);
module.exports = app;
apis.js:
module.exports = function(app){
app.get('/', function(req, res) {
res.send('OK');
});
app.post('/idea', function(req, res) {
...
});
};
Also, having module.exports = app in server.js is important as I have tests running and I want a instance of app everytime.
What am I missing?
Better approach :-
server.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: true});
app.use(express.static('public'));
var apis = require('./routes/apis');
app.use('/', apis);
module.exports = app;
apis.js :-
var router = require('express').Router();
router.post('/url',function(req,res,next){
//your code
})
module.exports = router
You need to pass in your express app into your apis module so it can attach the routes to your app. If you want to use app.use to put your routes in a different root path, you can create another express router, and attach your routes to that, then app.use that router:
server.js:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: true});
app.use(express.static('public'));
var apis = express.Router();
require('./routes/apis')(apis);
app.use('/', apis);
module.exports = app;
There's a couple different methods for connecting your app to your routes, and it looks to me like you are mixing them together, resulting in your error.
The fix already mentioned...
var router = require('express').Router();
router.post('/url',function(req,res,next){
//your code
})
module.exports = router
...works with the way you currently have your server.js file set up.
Another method that doesn't require you to modify your apis.js file is to require it in server.js using
require("./routes/apis.js")(app);
instead of
var apis = require('./routes/apis');
app.use('/', apis);
This ensures that the variable app is passed into the function in apis.js
The first version is recommended, but hopefully this explains why you are getting confused between the two, i.e. because the second is an alternate version.
See Differences between express.Router and app.get? for more information on why the router version is recommended.
Related
I have two questions:
Can I use cors() once in my server.js instead of calling and use it in all my router files?
Can I require express once in my server.js instead of calling it in all my router files?
My server.js now has no problems to handle CORS like below but the app also handles the users router.
server.js handles requests to /
const cors = require('cors');
const express = require('express');
const users = require('./routers/users');
const app = express();
app.use(cors());
app.use('/api/v1/user', users); // Register the user router
routers/users.js handles requests to /users
const cors = require('cors'); // Required again
const express = require('express'); // Required again
const router = express.Router();
router.use(cors());
If I don't use router.use(cors()) I will receive an CORS on the browser when I access /api/v1/users
Yes you need to use cors() only once for entire application.
No you need to require express in each file if you are segregating your routes in separate files
Folder structure:
+ index.js
+ routers
+ users.js
+ server.js
+ controllers
+ user_controller.js
How your index.js file should look like:
const cors = require('cors');
const express = require('express');
const serverRoutes = require('./routers/server');
const app = express();
// Allow cross origin access.
app.use(cors());
app.use('/', serverRoutes);
How your server.js file should look like:
const router = require('express').Router();
const userRoutes = require('./users');
router.use('/api/v1/user', userRoutes); // Register the user router
module.exports = router;
How your user.js file should look like:
const router = require('express').Router();
const userController = require('../controllers/user_controller');
router.get('/', (req, res) => {
userController.list(req, res); // or whatever your code is.
});
module.exports = router;
I have a simple express application boiler plated with Express Generator.
I am trying to run middleware to verify a JWT but none of my middleware seems to get run when testing with postman.
If I make a request from my browser, I can see the logs in the middleware run fine.
My app.js has a simple logger function which should run on all requests.
import token_verification from './middleware/token_verification';
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var api = require('./routes/api');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, '../views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/api', api);
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.use(token_verification);
const LOCALHOST = process.env.PORT || 3037;
app.listen(LOCALHOST, () => {
console.log(`Listening on ${LOCALHOST}`);
});
module.exports = app;
I have my routes/index.js with a simple GET route
import express from 'express';
const router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
As I said, when I got to http://localhost:3037/ in my browser, I can see my terminal logs "LOGGED" but when I make a GET request via post to the same URI, nothing is logged and appears no middleware runs.
EDIT:
Postman screenshot
I don't know why it's working from the browser but not from Postman (there's likely some headers that are being set by the browser and not by postman, but I don't see why that would matter).
What does matter, though, is that you're defining your logger after your routes, and since your GET route ends the response with res.render the middleware will not fire.
Remember, in the latest versions of Express, middleware fires in the order they're mounted on the app.
If you want the logger to always fire, reorder things:
var myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.use(token_verification);
app.use('/', index);
app.use('/api', api);
I'm trying to organize routes in express. But I'm having trouble getting a simple setup to work. I have two files, api.js, which has the routing info, and index.js, which runs the server.
However, when I try this, I get no response on localhost:3000.
api.js
var express = require('express');
module.exports = function() {
var router = express.Router();
router.get('/', function(req, res) {
res.send('im the home page!');
});
return router;
}
index.js
var express = require('express');
var app = express();
var router = require('./api');
app.use('/',router);
app.listen(3000);
console.log('Listening on port 3000!');
However, when I change api.js to this, it works:
api.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('im the home page!');
});
module.exports = router;
I don't understand why the bottom api.js works when the top one doesn't. Shouldn't module.exports return the same express Router in both cases?
The difference is that in the first version you're exporting a function that returns the router vs the second version where you're exporting the router itself.
In the first version, Express calls your exported function, passing it req and res, expecting it to somehow handle the request. The exported function of course is not designed to handle a request (it's just creating a router and returning it), so the request times out.
I'm using express in my app.js I set something like this
var express = require('express');
var app = express();
app.set('myVar', 'hello');
then in my controller I want to get the value. I do
var express = require('express');
var app = express();
console.log(app.get('myVar')) // undefineded
Any idea why?
Your controller creates a new, fresh instance of Express. If you want to be able to share variables, you need to pass the instance from app.js to your controller:
// app.js
var express = require('express');
var app = express();
app.set('myVar', 'hello');
require('./controller')(app);
// controller.js
module.exports = function(app) {
console.log(app.get('myVar'));
};
EDIT: judging by the comments, the issue isn't so much passing app around, but moving parts of the application to separate modules. A common setup to enable that would look like this:
// app.js
var express = require('express');
var app = express();
app.set('myVar', 'hello');
app.use('/api', require('./controller/auth'));
// controller/auth.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
console.log(req.app.get('myVar'));
return res.send('hello world');
});
module.exports = router;
In your example you are instantiating a second app that you then try to get the value from. You need to get from the exact same object:
var express = require('express');
var app = express();
app.set('foo', 'bar');
app.get('foo');
If you are new to express, you can use the cli generator to scaffold out an application that shows you a sane pattern how to use the same express instance throughout your whole application.
I tried to separate my node routing into two parts: HTML/App and REST. Here is what I've done:
app.js:
var appPort = process.env.PORT || 80;
var express = require('express');
var http = require('http');
var appRouter = require('./routes/index');
var restRouter = require('./routes/rest');
var app = express();
var srv = http.createServer(app);
app.set('port', appPort);
app.set('view engine', 'jade');
app.use(express.static(path.join(__dirname, 'public')));
app.use('/api/rest/', restRouter); // this seems not working .. I never get the expected response
app.use('/', appRouter); // I get this even with localhost/api/rest/...
var server = srv.listen(app.get('port'), function() {
debug('Express server listening ' + server.address().address + ':' + server.address().port);
});
index.js:
var express = require('express');
var router = express.Router();
router.get('/*', function (req, res) {
res.send('HOME')
});
module.exports = router;
rest.js
var express = require('express');
var router = express.Router();
router.get('/api/rest/*', function(req, res) {
res.send('REST API');
});
module.exports = router;
My questions:
1. It's possible in general to build multiple routers in this way?
2. Does the sequence of get.use matter, and/or do I have to deal with 'next'?
3. In case I would like to access a database inside the router can I hand over a parameter like this:
// ...
var client = new pg.Client(dbConnection);
// ...
app.use('/', appRouter(client));
1) It is possible to build multiple routers this way.
Because you are using this:
app.use('/api/rest/', restRouter);
your route calls in rest.js will be relative to /api/rest/ which means your code should be modified in rest.js to look like this:
router.get('*', function(req, res) {
res.send('REST API');
});
I would also encourage you to see the Express multi-router example on GitHub. It illustrates this point very clearly by showing a REST app with versioned routes.
2) The order of things matter
See the Express documentation for app.use and you will note:
Middleware functions are executed sequentially, therefore the order of
middleware inclusion is important.
If you reverse the order of your app.use calls, the router.get('/*', function (req, res) { line in index.js will catch everything before you get to other routes...defeating your purpose.
Also, if you don't call next, Express has no way to know that you are done or even that you want to continue to the next middleware or route.
3) The database question is a modules/scope question
This is more of a scope question than an Express question. I'd suggest looking up some of the excellent writing about javascript scope and also on how Node handles modules.