RESTful Express Mongoose & Backbone - Backbone mod

2019-07-30 13:17发布

问题:

I'm developing a Node app using Express, Mongoose and Backbone with Marionette.

All routes are working well except the delete route.

If I call this.model.destroy, I always get this error:

DELETE http://localhost:3000/api/user 404 (Not Found) 

The 404 is returned in Express's delete route, like if Express didn't support it, but I've seen numerous examples across the web using it.

Here's my setup:


Mongoose Schema:

var UserSchema = new mongoose.Schema(
{
    name: String,
    email: String,
    age: Number
});

User = mongoose.model('User', UserSchema);

ExpressJS Route: (not working)

app.del('/api/user/:id', user.remove);

OR

app.delete('/api/user/:id', user.remove);

This route is called by backbone model.destroy(), but returns error 404.


ExpressJS user.js controller: (works but is not reached because of the 404 before)

exports.remove = function(req, res)
{
  var id = req.params.id;

  User.findById(req.params.id, function(err, user) 
  {
      user.remove(function(err) 
      {
          if(err) res.json(err);
          res.json('all good');
      });
   });
};

BackboneJS Model

var User = Backbone.Model.extend({
    idAttribute: "_id",
    url: '/api/user/',
});

BackboneJS client View

var UserView = Backbone.Marionette.ItemView.extend(
{
    template: Handlebars.compile($('#userView').html()),
    events: 
    {
        'click .delete-button': 'deleteUser'
    },
    deleteUser: function(event)
    {
        this.model.remove();
    }
});

I always get this error:

DELETE http://localhost:3000/api/user 404 (Not Found) 

HOWEVER it works if I use this direct ajax call:

jQuery.ajax({
  url:'/api/user/' + this.model.id,
  type: 'DELETE',
  success:function(data, textStatus, jqXHR)
  {

  }
});

So, why does this work if I call the route via Ajax, if Backbone internally also uses Ajax? Why does Backbone fail to make such a simple model.destroy()?

Is there a way to configure Backbone Model.destroy method to work well like the Ajax example above? Thanks

回答1:

Found the problem. Backbone model.remove() was not sending the id because I was using "url" in this way:

Backbone.Model.extend({
    url: '/users',
    //...
});

That will tell Backbone to use exactly /users as the URL for all actions.

To ensure sending the id using "url", one can use a function:

url: function() { 
    return '/list_items/' + encodeURIComponent(this.id) 
}

Or even better use "urlRoot" instead of "url", let the default "url" function add the id:

urlRoot: '/users'

Working like a charm with urlRoot