Sending DELETE request in a link in nodejs express app - javascript

I have a route which accepts DELETE requests, and I know that with Express you can add
<input type="hidden" name="_method" value="delete" />
to a form that sends a POST request to the url.
However, how would you do this with a link instead of a form?

This is not supported for GET requests:
methodOverride() only checks req.body (POST arguments) and request headers - neither can be set for a regular link (you can however set custom headers in AJAX requests even if they use GET).
This make senses since otherwise it could be a major issue even when using CSRF tokens. You can never know when a browser will decide to prefetch a link - so GET requests should never perform actions such as deleting things.
If you really need it and do not care about the drawbacks, consider writing a custom function:
function methodOverrideGET(key) {
key = key || "_method";
return function methodOverrideGET(req, res, next) {
if (req.originalMethod != req.method) {
// already overridden => do not override again
next();
return;
}
req.originalMethod = req.method;
if (req.query && key in req.query) {
req.method = req.query[key].toUpperCase();
delete req.query[key];
}
next();
};
};
Now you can .use(methodOverrideGET) after .use(methodOverride) and then simply add _method=DELETE to the query string.

Related

Clone/relay exact request to another URL (nodejs)

I'd like to clone/relay the exact request to another URL in native NodeJs. For example, if you send a POST request to my site "example.com", it will send the exact same request you sent to another URL "example2.com" (data, headers etc). How could I achieve that?
You can use proxy middleware to duplicate the request. For example http-proxy-middleware will allow you to proxy the request to another server, but from what I can tell, you can only modify the response. Which isn't optimal if you don't want to wait on the proxy. You might just grab the main proxy library itself, something like:
const httpProxy = require('http-proxy');
const proxyMiddleware = httpProxy.createProxyMiddleware({
target: 'http://www.example2.com',
selfHandleResponse: true
});
const customProxyMiddleware = (req, res, next) => {
proxy.web(req, res);
next();
};
// This passes all incoming requests to the proxy but does not handle
// any of them. It simply passes it along.
app.use('/', customProxyMiddleware);
This code may not work exactly as intended but it should be a good starting point for what you are attempting.

Handling POST request on a GET route (express.js)

I am new to express and node together and seem to be stuck, with what seems to be, a simple issue. I have an API route that uses GET. Route:
app.get('/api/v1/all', getAllWords);
Then inside of the getAllWords callback function, I want to check if the request that was sent was of GET or POST. This is the code I have to check the request method:
function getAllWords(request, response) {
let reply;
if (request.method === 'GET') {
console.log('This was a GET request');
// handle GET here...
}
if (request.method === 'POST') {
console.log('This was a POST request');
reply = {
"msg": "HTTP Method not allowed"
};
response.send(reply)
}
}
When I use Postman to send off a GET request it works just fine. But when sending a POST request I get the generic express.js "Cannot POST /api/v1/all".
Why did it the response.send(reply) not work for the POST method?
app.get(...) define endpoint that only matches with GET method. If you want to handle POST method you must supply seperate middleware in app.post(...)
You can make use of app.all(...) to handle both GET and POST requests but it also accepts other kind of requests such as PUT and DELETE. I prefer separating the GETand POST request though.

Redirecting get to post? res.redirect to POST

Here in the GET /facebook route i receive the authorization code from front-end after receiving that, i have to make a POST request to /facebook/signin
How can I redirect GET /facebook to POST /facebook/signin
router.get('/facebook', (req, res) => {
// res.send(req.query.code);
res.redirect('/facebook/sign'); // = GET /facebook/sign
});
POST route
router.post('/facebook/sign', (req, res, next) => {
console.log(req.query.code);
// i will do mine stuff....
});
You can also write 1 handler method and use it in both routes;
function doFacebookSignIn(req, res) {
// Your code here.
}
or
// Must be defined before using it in code.
var doFacebookSignIn = function(req, res) {
// Your code here.
};
router.get('/facebook', doFacebookSignIn);
router.post('/facebook/sign', doFacebookSignIn);
But as I pointed out in the comments, you should be aware that when using a request body in a GET request, there are some things to consider.
You cannot redirect GET to POST, a redirect is used to notify an HTTP client that a resource has changed location and should attempt the same request using the new location.
It is noted in the RFC that in some cases POST will be downgraded to GET when the request is re-issued.
Note: When automatically redirecting a POST request after
receiving a 301 status code, some existing HTTP/1.0 user agents
will erroneously change it into a GET request.
If a POST request is expected on the server, then the client should send a POST request rather than a GET request.

Can I alert the user from the route/middleware?

I am using the route to check if a token is valid or not. If it isn't I route the user to the log in page. I want to let the users know they're being logged out either as an alert or on the page.
What happens is a user clicks on Link A (to take them to another page on the website), the route calls a validate.js file:
route.js
var checkToken = require('../validate.js');
router.use(checkToken.checkToken);
This then calls the validate.js file which makes a HTTP call to check
if the token is valid, if it isn't it redirects the user to the Login
page:
validate.js
var checkToken = function(req, res, next) {
if (config.enableTokenValidation) {
var usersToken = req.user.token;
validateToken(receivedToken, req.requestId, function(err, response, body) {
if (err || response.statusCode != 200) {
console.log("Error, token is not valid");
res.redirect("/auth/logout/");
} else {
return next();
}
});
How can I send a message to the loginView.js file so that I can display the error in the front end (or create an alert)?
But as this happens in the middleware and it is other routes to other pages within the program that trigger the validation check, the login page doesn't make the check and therefore I can't get the response there to alert the user.
If there any way of achieving this using the way I'm going about it, or are there any other ways I can go about it?
Many Thanks
Instead of doing
res.redirect();
Why do not you send an error message like
res.status('401').send({error:'Invalid Token'});
Then you can take the necessary steps in the errorHandler() of the api call.
You can return an object that contains a method that fires an Alert message (or a change in your HTML, if you want to change the view). Then you use yourObject.method from the Frontend.

Authentication and authorization with Flatiron's Resourceful & Restful

I want to implement authentication and authorization in the Flatiron stack (using Flatiron, Resourceful and Restful). I want to require that a user has the necessary permissions, when trying to change a resource. In the Restful Readme file, there's a note about authorization:
There are several ways to provide security and authorization for
accessing resource methods exposed with restful. The recommended
pattern for authorization is to use resourceful's ability for before
and after hooks. In these hooks, you can add additional business logic
to restrict access to the resource's methods.
It is not recommended to place authorization logic in the routing
layer, as in an ideal world the router will be a reflected interface
of the resource. In theory, the security of the router itself should
be somewhat irrelevant since the resource could have multiple
reflected interfaces that all required the same business logic.
TL;DR; For security and authorization, you should use resourceful's
before and after hooks.
So authorization can be handled by Resourceful's hooking system.
My actual problem is the authentication process at the beginning of every HTTP request.
Let's say I have a resource Post, a User and a resource Session. The REST API is being defined by using Restful. My main concern for this question is to ensure that a user has a session when creating a post. Other methods like save, update or for other resources like creating a user should work analogous.
File app.js:
var flatiron = require('flatiron');
var app = flatiron.app;
app.resources = require('./resources.js');
app.use(flatiron.plugins.http);
app.use(restful);
app.start(8080, function(){
console.log('http server started on port 8080');
});
File resources.js:
var resourceful = require('resourceful');
var resources = exports;
resources.User = resourceful.define('user', function() {
this.restful = true;
this.string('name');
this.string('password');
});
resources.Session = resourceful.define('session', function() {
// note: this is not restful
this.use('memory');
this.string('session_id');
});
resources.Post = resourceful.define('post', function() {
this.restful = true;
this.use('memory');
this.string('title');
this.string('content');
});
resources.Post.before('create', function authorization(post, callback) {
// What should happen here?
// How do I ensure, a user has a session id?
callback();
});
There's also a runnable version of the code (thanks #generalhenry).
So assume a user trying to create a post, already has been given a session id, that is sent with every request he makes by a cookie header. How can I access that cookie in the before hook (i.e. the authorization callback)?
The example can be started with node app.js and HTTP requests can be made using curl.
Keep in mind that these guidelines are for authorization process. If you need to use sessionId you can access it either way: req.sessionID, req.cookies["connect.sid"].
By checking requests this way you will be sure every users have valid session id.
app.use(flatiron.plugins.http, {
before: [
connect.favicon(),
connect.cookieParser('catpsy speeds'),
function(req, res) {
if (req.originalUrl === undefined) {
req.originalUrl = req.url;
}
res.emit('next');
},
connect.session({secret : 'secter'}),
function(req, res) {
console.log('Authenticating...');
console.dir(req.session);
//any other validation logic
if (req.url !== '/login' && typeof req.session.user == 'undefined') {
res.redirect('/login');
} else {
res.emit('next');
}
}
]
});
Here is project example using this approach.

Categories