I'm new to javascript. I'm trying to make a RESTfull API using Node.js and Express.js
My directory structure is as follows
/server.js
/api/api.js
/api/location/location.js
I want to make the API modular. I want that all the requests (get/post/delete/push) beginning with /api/* to be handled by api.js and whatever routing be required, api.js should route it to proper module.
For example, if someone requests GET /api/location/abc/xyz then api.js will transfer control to location.js which will then transfer to abc.js which will finally transfer to xyz.js stored in directory /api/location/abc/xyz/xyz.js
How can I achieve this?
Code so far:
/server.js
var express = require('express');
var app = express();
var api = require('./api/api.js');
var location = require('./api/location/location.js');
//app.use('/api/location', location); //This works, but I want api.js to handle sub-routes!
app.use('/api', api);
app.get('/', function(req, res){
res.end('successful get/');
});
app.listen(12345);
/api/api.js
module.exports = function(req, res, next) {
res.end('successful get /api');
next();
};
//Add code to handle GET /api/location
/api/location/location.js
module.exports = function(req, res, next){
res.end('from location!');
next();
}
You would use express.Router([options]).
And write it that way:
/api/api.js
var router = require('express').Router();
router.get('/location', require('./api/location') );
module.exports = router;
/api/api/location.js
module.exports = function(req, res, next){
res.end('from location!');
}
And don't call next(); if you ended the response. You only call next() in your callback if you don't handle the response.
I don't know how complex your REST api will be later. But try to to keep the routing in a small number of file. Having a callback for the routing in an own file like /api/api/location.js is most likely not the best idea.
Related
Introduction
I have built some back end functionality in Node (First time using Node). Problem is that the whole thing was built in one page (index.js) so now im following a few basic tutorials and setting out express router middleware and now trying to follow a modular MVC approach,
This code is simple but brakes when I separate into two pages Server.js and config.js. I know its a simple problem but i cant spot it. can someone help spot the problem and maybe improve the structure ?
Problem
I go to http://localhost:8080/about or a different route and I get
Cannot GET /about
rather than the correct print out.
back-end/server.js
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
// get an instance of router
var router = express.Router();
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Server has started!! ' + port);
back-end/config.js
router.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
router.get('/', function(req, res) {
res.send('im the home page!');
});
// sample route with a route the way we're used to seeing it
router.get('/sample', function(req, res) {
res.send('this is a sample!');
});
router.get('/about', function(req, res) {
res.send('im the about page!');
});
app.route('/login')
.get(function(req, res) {
res.send('this is the login form');
})
.post(function(req, res) {
console.log('processing'); // shows on console when post is made
res.send('processing the login form!'); // output on postman
});
app.use('/', router);
As #SLaks said in his comment, you need to import (require) your backend/config.js file. But it's not as simple as that...
In node, variables are scoped to the file in which they appear, so if you simply add require('./config') to your server.js file, that's not going to work either, because the router variable in config.js is local to that file - it's not going to know about the router variable in server.js.
The solution to this is to have the config.js file export a function which the server.js file can use to configure stuff. For example
config.js
module.exports = function(router) {
// set up your router here with router.use, etc.
};
server.js
var configure = require('./config');
// after you set up your express router...
configure(router);
// now start listening
This question is very similar to How to disable Express BodyParser for file uploads (Node.js). The answer they have provided is for Express3 and I have tried the solution with the updated Express 4 and it does not seem to work.
I'm using Node.js + Express to build a web application. I am using another library,BodyParser,to parse post parameters. However, I would like to have more granular access to multipart form-data POSTS as they come - I need to pipe the input stream to another server, and want to avoid downloading the whole file first.
All file uploads are parsed automatically and uploaded and available using "request.files" before they ever get to any of my functions.
Is there a way for me to disable the BodyParser for multipart formdata posts without disabling it for everything else?
This is my app.js file. In here I am defining an authentication route which shouldn't except any files just a token (POST parameter). I am also defining another route called upload. This route accepts a file and also POST parametes (form-data). This route only gets called if the authentication route allows it. So in the authetnication route I don't want form-data to be allowed, but in the upload route I do. So when I get a request to uplaod something it will go through the auth route and then the upload route. Due to this I need to allow the auth route to allow files (form-data) which I do not want. So I want bodyparser to work in the auth route while I use mutler (another library) in my upload path to parse my upload files. In my real application though of course I have many more routes and would like to code it as cleanly as I can with the least amount of redundancy.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
var route_auth = require('./routes/auth');
app.use('/api/post/*', route_auth);
var route_upload = require('./routes/post/upload');
app.use('/api/post/upload', route_upload );
app.listen(3000, function() {
console.log('Server listening on port 3000!')
});
My auth route looks something like this:
router.post("/", function(req, res, next) {
if(everythingiscool){
return next()
}
next(err);
});
My upload route looks like this:
var express = require('express');
var router = express.Router();
var multer = require('multer')
var upload = multer({ dest: 'uploads/' });
router.post("/", upload.single('avatar'), function(req, res, next) {
//work with req.file
});
Wrap the bodyParse middleware in a function that checks if the request body's Content-Type is multipart or not:
var isMultipart = /^multipart\//i;
var bodyParser = require('body-parser');
var urlencodedMiddleware = bodyParser.urlencoded({ extended: true });
app.use(function (req, res, next) {
var type = req.get('Content-Type');
if (isMultipart.test(type)) return next();
return urlencodedMiddleware(req, res, next);
});
Instead of disabling, why not enable the middleware on the routes/routers where you need it?
For individual routes, you can just add it as another argument before your actual route handler, for example:
app.post('/upload', bodyParser, (req, res) => {
// route logic here
});
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 want to create a login and registration page for a web application. I have been using this tutorial:
https://thinkster.io/mean-stack-tutorial
However, I want to modify it so everything is not in the same index.ejs file (I do not just want to use "include") but rather on a separate page entirely. In order to do this, I created a register-login.ejs file and a register-login.js file in addition to the index.js file. In my "register-login.js" file I added:
`router.get('/register-login', function(req, res, next) {
res.render('register-login');
});
`
Then in my app.js file I added:
var routes = require('./routes/register-login');app.use('/register-login', routes);
Unfortunately, this attempt results in a 404 Error. How do I properly separate the provided code in the above tutorial into two separate pages: index.js and register-login.js, index.ejs and register-login.ejs and connect them properly?
register extra routes on the router.
var app = express();
var router = express.Router();
router.get('/register', function(req, res, next) {
res.render('./views/register');
});
router.get('/login', function(req, res, next) {
res.render('./views/login');
});
then use them all with app.use('/', router);or app.use(require('./routes/user')); if you export the router and require it
Having a rough time adding Socket.io in my Express 4 Routes. In my routes/index.js I have:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/message', function(req, res) {
console.log("Post request hit.");
// res.contentType('text/xml');
console.log(appjs);
io.sockets.emit("display text", req);
// res.send('<Response><Sms>'+req.body+'</Sms></Response>');
});
module.exports = router;
but io is undefined. I have seen several examples of how to do this, but none that worked for me. Any help would be appreciated.
You need to pass your socket.io variable to the router module so that it has access. You could do this by wrapping your module in a function call.
var express = require('express');
var router = express.Router();
/* GET home page. */
var returnRouter = function(io) {
router.get('/', function(req, res, next) {
res.render('index', {
title: 'Express'
});
});
router.post('/message', function(req, res) {
console.log("Post request hit.");
// res.contentType('text/xml');
console.log(appjs);
io.sockets.emit("display text", req);
// res.send('<Response><Sms>'+req.body+'</Sms></Response>');
});
return router;
}
module.exports = returnRouter;
Then, whever you import this route you would call this function like: require(./routefile)(io)
Here's a good article about creating modules that require being passed a variable: Node.Js, Require and Exports
How about exploiting events? This could add an extra layer of self-awareness to the app, including socket messaging.
Since express's app() inherits from node's eventEmitter, I app.emit('EVENT_NAME', payload) at any point in my route handlers,
and then just handle that with app.on('EVENT_NAME', function(payload){})
with any logic available. I'm using it in my current setup.
This is super old, but I was looking to do the same thing and didn't find a suitable answer. I came up with a good solution using app.set('socketio', io) and req.app.get('socketio') in my route. I was then able to create a reference to the sender's socket in my route without using io.on().
See the answer I added here for the code:
Use socket.io inside a express routes file