I have a route like this -
server.get({
url : '/reguser/:useremail',
name : 'pre-register-user'
}, function(req, res, next) {
return next();
}, function sendResult(req, res, next) {
var user = { 'email' : req.params.useremail }
// Create a new user on the DB
res.contentType = 'application/json';
// rest of the processing.
}
Works if it gets called with /prereg/someone%40someemail.com. But if it gets /prereg/someone#someemail.com it does not process at all. I am using Nginx in the front and rewrite in it replaces the %40 with # even though the web-page is sending urlencoded string with %40.
Any way out of this?
Related
My nodeJS Api needs to return HTML or Json based on the header. If the header is:
Accept = application/json
The Api needs to return Json else my Api needs to return a HTML file.
this is the code I use on my routes:
var app = express();
app.use('/auth', require('./routes/Authenticate'));
In the Authenticate file I catch /login, and do the login stuff. if it succeeds I redirect to /users. In the /users I check for the Accept with an if statement:
router.get('/users', function(req,res){
if(req.get('Accept') === 'application/json'){
res.json({ success: true, user: req.user });
} else {
res.render("account/profile") //redirect to the file
}
});
This works(from this solution) but is there a better way? Because there are like 20 endpoints and the application is growing and this will be a mess for every endpoint.
you can split these actions into 2 functions. One to verify the content type and an other to doing your actions.
router.get('/users', checkIfJson, action);
function checkIfJson(req, res, next) {
if(!(req.get('Content-Type') === 'application/json')) {
res.render("account/profile");
return;
}
next();
}
function action(req, res) {
res.json({ success: true, user: req.user });
return;
}
If you write your code like that you can reuse your checkIfJson into other routes.
You can wrap router.get function with a custom function
router.wrappedGet = function (path, callback) {
router.get(path, function (req, res) {
if (req.get('Content-Type') === 'application/json') {
res.render = res.json;
}
callback(req, res);
})
};
Here's what I've doneāseems pretty straightforward.
router.get("/foo", HTML_ACCEPTED, (req, res) => res.send("<html><h1>baz</h1><p>qux</p></html>"))
router.get("/foo", JSON_ACCEPTED, (req, res) => res.json({foo: "bar"}))
Here's how those middlewares work.
function HTML_ACCEPTED (req, res, next) { return req.accepts("html") ? next() : next("route") }
function JSON_ACCEPTED (req, res, next) { return req.accepts("json") ? next() : next("route") }
Personally I think this is quite readable (and therefore maintainable).
$ curl localhost:5000/foo --header "Accept: text/html"
<html><h1>baz</h1><p>qux</p></html>
$ curl localhost:5000/foo --header "Accept: application/json"
{"foo":"bar"}
Notes:
I recommend putting the HTML routes before the JSON routes because some browsers will accept HTML or JSON, so they'll get whichever route is listed first. I'd expect API users to be capable of understanding and setting the Accept header, but I wouldn't expect that of browser users, so browsers get preference.
The last paragraph in ExpressJS Guide talks about next('route'). In short, next() skips to the next middleware in the same route while next('route') bails out of this route and tries the next one.
Here's the reference on req.accepts.
Consider the following code from an express app:
var express = require('express');
var router = express.Router();
var standupCtrl = require('../controllers/standup.server.controller');
/* GET home page. */
router.get('/', function(req, res) {
return standupCtrl.list(req, res);
});
/* POST filter by member name - home page. */
router.post('/', function(req, res) {
return standupCtrl.filterByMember(req, res);
});
// ............ more code here
module.exports = router;
exports.list = function(req, res) {
var query = Standup.find();
query.sort({ createdOn: 'desc'}).limit(12).exec(function(err, results){
res.render('index', {title: 'Standup - List', notes: results});
});
};
exports.filterByMember = function(req, res) {
var query = Standup.find();
var filter = req.body.memberName;
query.sort({ createdOn: 'desc' });
if (filter.length > 0)
{
query.where({ memberName: filter})
}
query.exec(function(err, results) {
res.render('index', { title: 'Standup - List', notes: results });
});
};
I know that when submitting a form you can specify a
method = get/post
For this scenario (where nothing such has been specified) , how does the server know which to trigger (post or get) when user navigates to '/' (e.g. Homepage)?
More generally, My question is:
What events trigger a Post/Get action (if not explicitly specified) ?
(PS: I know typing anything in the address bar of a browser triggers a GET request)
Thanks a lot in advance!
HTTP GET is pretty much the default everywhere if you don't specify otherwise.
Most POSTs are the result of either a form submit or an explicit call via AJAX or as a web service call (like RPC from another server). You CAN handcraft POST requests using programs like curl, but again that would be rare. In every toolkit I've seen, it's GET by default.
And rarely (VERY), you might find some RPC provider (such as an IoT or other embedded device) that only speaks POSTs (to save on code space).
I am not really sure what to title this, but I'm new to Node.js. I just found a neat REST API project on GitHub to implement but I'm not sure how I can split all GET and POST etc. to separate files.
I have one singular api.js file where I have
function API_ROUTER(router, connection, md5) {
var self = this;
self.handleRoutes(router, connection, md5);
}
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
router.get("/", function(req, res) {
res.json({"Message" : "Hello World !"});
});
};
module.exports = API_ROUTER;
Now how can I create a sibling other.js and use:
var api = require('./api.js');
// Create router.get, router.post etc. here?
but I'm not sure how I can split all GET and POST etc. to separate files.
One way you can organize your routes would be to have a separate object for each route that has the handlers (separated by HTTP methods) and other needed info such as the path:
api/home.js
module.exports = {
path: '/',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Hello World !"});
},
'post': {
// ...
}
// ...
}
}
api/other.js
module.exports = {
path: '/other',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Other !"});
},
// ...
Then you can load all of these inside the handleRoutes method:
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
var routes = ['home', 'other'];
routes.forEach(function(name) {
// load the current route object (NOTE: you should use the path module for determining file path in a cross-platform manner)
var routeObject = require('./' + name + '.js');
var apiPath = routeObject.path;
var handlers = routeObject.handlers;
var methods = Object.keys(handlers);
// assign handlers for each method
methods.forEach(function(method) {
router[method](apiPath, handlers[method]);
});
});
};
This will install all your routes with the appropriate information and handlers.
Now you can call this code by instantiating your API_ROUTER with the necessary data:
// initialize the api (and handle the routes internally)
var Api = new require('./api.js')(router, connection, md5);
If you implement a RESTful API, then you should keep in mind that this is just one way how you can provide data, and you might want to change it in future, as of that the API will most of the time only be a translation layer.
Normally you will split your code based on the resources, and the code that is handling the request won't have so much logic, it will just take the request and pass it to you internal API. For that purpose you not really need an additional layer if you already use express.js or a similar library.
In express the app.use([path,] function [, function...]), already provides the functionality you would need to modularize your code. For each resource your will create an own express.Router that itself also might mount another sub module. So for this part you do not really need a library.
When might a library be useful:
if it automatically translates thrown errors to the correct response codes
if it includes a tool to automatically create a documentation to your API
if it fully abstracts the underlaying routing system so that you can hook into express, hapi, ... without the need to change the code.
Here how a setup with express.js could look like
./lib/rest/customer.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.params.id
}, function(err, customer) {
if (err) {
res.status( /*correct status code*/ ).send( /*depending on the api return json, xml, ....*/ )
} else {
res.send( /*depending on the api return json, xml, ....*/ )
}
})
});
router.delete('/:id', function(req, res, next) {
customerSystem.delete({
id: req.params.id
}, function(err) {
//...
});
});
router.post('/', function(req, res, next) {
//...
});
//save the customer id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.customerId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;
./lib/rest/customer-address.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.customerId
}, function(err, customer) {
// ...
})
});
/* ..... */
//save the address id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.addressId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;
I would like to know how to pass parameters when using the official webapp package to listen to incoming HTTP requests on a particular route.
Here is an example code:
WebApp.connectHandlers.use("/hello/:myParam", function(req, res, next) {
res.writeHead(200);
res.end("Your param is", req.myParam);
});
The above Express-like example does not work with WebApp. After some experiments, I now know I can access query params using req.query. But does WebApp allow you to access regular parameters?
I know this question is more than 1 year old, but there seems to be no built-in method yet, so here's how I did it. There is an npm package called connect-route (I'm almost sure there are others). Install it with npm i --save connect-route. Then in your code:
import connectRoute from 'connect-route';
WebApp.connectHandlers.use(connectRoute(function (router) {
router.get("/post/:id", function(req, res, next) {
console.log(req.params); // { id: 1 }
res.writeHead(200);
res.end('');
});
router.get("/user/:name/posts", function(req, res, next) {
// etc. etc.
});
}));
Works like a charm for me with version 0.1.5
I don't know of a connect middleware that does that (it might exist though, in which case you could plug it in), but it's easy enough to replicate that behavior:
WebApp.connectHandlers.use("/hello/", function(req, res, next) {
var parts = req.url.split("/");
res.writeHead(200);
res.end("Your param is " + parts[1]);
});
Not quite the same but seems to work well. Of course, most people would just use iron-router for something like this, but I'm assuming you want to avoid that for some reason.
Straight out of the box, you can use query instead of Params like you do in express. There's no real downside other than URL personal preference for using Parameters instead of Query.
Here's an example, providing a PDF from a route using connectHandlers:
WebApp.connectHandlers.use("/billPreview", function(req, res, next) {
var re = urlParse.parse(req.url, true).query;
if (re !== null) { // Only handle URLs that start with /url_path/*
// var filePath = process.env.PWD + '/.server_path/' + re[1];
console.log('Re: ',re);
var filePath = process.env.PWD + '/.bills/pdf/' + re.id +'/'+re.user+'/lastTicket.pdf';
var data = fs.readFileSync(filePath, data);
res.writeHead(200, {
'Content-Type': 'application/pdf'
});
res.write(data);
res.end();
} else { // Other urls will have default behaviors
next();
}
});
I am a newbie in Node.js (and Express) and I am trying to make sense of this. Say I have a website with 3 pages (can be GET or POST): /, /page1, /page2. What should I do so that every page is handled by a separate JS file?
app.all('/', function(request, response)
{
// Get home.js to handle this request and response
});
app.all('/page1', function(request, response)
{
// Get page1.js to handle this request and response
});
app.all('/page2', function(request, response)
{
// Get page2.js to handle this request and response
});
Better yet, is there a way to define a wildcard so there is not so much repetition? Something like this:
app.all('*', function(request, response)
{
// Get *.js to handle this request and response. * is whatever the URI string is
});
The trick here is that app is local to the file that creates it. So you have to get that object to the scope of the other files.
Each other file should export a funciton that you can pass your app instance to so it can register new routes. An approach like this should work.
// home.js
exports.register = function(app) {
app.all('/', function(request, response) { ... });
};
// page1.js
exports.register = function(app) {
app.all('/page1', function(request, response) { ... });
};
// page2.js
exports.register = function(app) {
app.all('/page2', function(request, response) { ... });
};
//server.js - setup the app
app = express.createServer();
require('./home').register(app);
require('./page1').register(app);
require('./page2').register(app);
And for the second part of your question, you want to share some setup methods?
app.all('*', function(req, res, next) {
res.header 'x-snazzy-header', 'Im so snazzy'
next()
});
app.all('/page/:id', function(req, res) {
res.send('content for page #'+ req.params('id'));
});
First, you can use * or named params like /users/:id, to match a range of routes. And if you want to do some common setup, you can actually execute 2 routes. The route handler takes an optional third argument next. When invoked, it will try to find the next route to match. So you can setup things like common headers for a bunch of routes with it.
Continuing my discussion with #Alex. Here's how I did it. Any gotcha?
// app.js
var EXPRESS = require('express');
var URL = require('url');
var PATH = require('path');
var app = EXPRESS.createServer();
app.all(/^\/([a-zA-Z0-9-]+)$/, function(request, response, next)
{
var page = request.params[0];
if (PATH.existsSync(__dirname + '/' + page + '.js'))
{
require('./' + page).handleRequest(request, response, next);
}
else
{
next();
}
});
app.all('*', function(request, response)
{
response.send('Catch all');
});
// --- truncated for brievity
// page1.js
exports.handleRequest = function(request, response, next)
{
response.send('Howdy!');
};