Daniel Tate
Daniel Tate

Reputation: 2153

Express cannot PUT/DELETE method. What is going wrong?

Ok So I have a simple node.js / express.js / mongodb app set up here with my config as follows.

var express = require('express'),
    mongoose = require('mongoose');
    http = require('http');

var app = express();

    app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');

    //middleware stack
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(__dirname + "/public"));
});

mongoose.connect("mongodb://localhost/hello");

The problem lies when I try to make PUT or DELETE requests. My form is this simple

<form method="POST" action="/users/#{user.name}">
    <input type="hidden" name="_method" value="PUT"/>
</form>

Now my router catches the route with the express .put() method

app.put('/users/:name', function(req, res) {

    var b = req.body;

    Users.update(
        { name: req.user.name },
        { name: b.name, age: b.age, email: b.email },
        function(err) {
            res.redirect('/users/'+b.name);
        });
})

When I make the request I simply get a "Cannot PUT" or "Cannot DELETE" error.

I have tried to make this same request via chomes RESTful client with the same result.

I have read a topic witch has the same problem as me although following the comments the answers did not solve my problem.

Questions I have looked into expressjs support for method delete and put without the methodoverride

Are the PUT, DELETE, HEAD, etc methods available in most web browsers?

Along with a few others. I have also referenced the express.js and mongo documentation several times. I just cant think what could be going wrong.

Any help is appreciated.

Upvotes: 21

Views: 61784

Answers (7)

Soheil Rezae
Soheil Rezae

Reputation: 11

one solution is to use cors middleware for you PUT,PATCH and DELETE requests like this in your app.js file like this:

first install the cors package via npm :

npm i cors

then add the following code to your app.js:

const cors = require('cors')

app.use(cors())

Upvotes: 1

yaya
yaya

Reputation: 8243

Change res.redirect('path') to res.redirect(303, 'path')

In Put and Delete, if you want to redirect to get address, you should pass 303 as first parameter. (source)

Upvotes: 0

Encrypted Drink
Encrypted Drink

Reputation: 91

app.post("/movies/:id") is one solution. If you still want to use app.put("/movies/:id") then try this:

  1. Install method-ovveride from npm.
  2. Require it in your app.js file.
  3. Open the form from where you wanna invoke PUT request
  4. make sure your form has the following attributes:

    action="/movies/<%= movies._id %>?_method=PUT " method="POST" >

These two solutions worked for me. If you are following REST, then use the method-ovveride else app.post() will also do the trick

Upvotes: 0

Anthony Cantellano
Anthony Cantellano

Reputation: 99

If your using method override, make sure you have declared it before you use your routes. That was the problem I was having.

Upvotes: 1

Dan Ross
Dan Ross

Reputation: 3691

Unless there is strange magic at work, your form makes a POST request, not a PUT. If you want to PUT, I would suggest using the jQuery.ajax function with a type: 'PUT' parameter, like this answer, from a form handler, see jQuery.submit. Don't forget to return false so that the form doesn't submit twice.

Upvotes: 1

user568109
user568109

Reputation: 47993

Update

As Jonathan Lonowski pointed out PUT can also be used, so you can ignore my old answer. Getting Cannot PUT or Cannot POST errors, means your callback is not executing successfully. My guess is that Users.update is failing, which is why it cannot POST or PUT. Can you check it.

Old answer

Try changing this line

app.put('/users/:name', function(req, res) {

to

app.post('/users/:name', function(req, res) {

since you are trying to submit the form

Upvotes: 14

Jonathan Lonowski
Jonathan Lonowski

Reputation: 123453

Is the <form> you listed in a view or a static file under __dirname + "/public"?

Within a static file, the #{user.name} probably isn't being replaced with the user's name and will be treated as a URL Fragment.

The <form> will actually submit to /users/ rather than /users/:name since that's the path:

console.log(url.parse('/users/#{user.name}'));

{ hash: '#{user.name}',
  pathname: '/users/',
  path: '/users/',
  href: '/users/#{user.name}' }

The <form> should be generated from a view if it isn't since the action needs to be dynamic and data-driven. With Jade and assuming user is a member of locals, that would be:

form(method='POST', action='/users/' + user.name)
  input(type='hidden', name='_method', value='PUT')

Upvotes: 3

Related Questions