Angular.js: 为什么 $resource 没有用于更新模型的 PUT?

创建于 2014-10-28  ·  20评论  ·  资料来源: angular/angular.js

是否可以使用createupdate操作来扩展$resource

Example: 
{ 'get':    {method:'GET'},
  'save':   {method:'POST'},
  'create': {method:'POST'},
  'update': {method:'PUT'},
  'query':  {method:'GET', isArray:true},
  'remove': {method:'DELETE'},
  'delete': {method:'DELETE'} };

是否也可以覆盖save操作以在 id 为空时调用create在设置 id 时调用update

ngResource high public api not core inconvenient feature

最有用的评论

var notes = $resource('/notes/:id', null, {
  'update': { method:'PUT' }
});

notes.prototype.$save = function() {
    if (this.id) {
        return this.$update();
    } else {
        return this.$create();
    }
};

所有20条评论

因为其他人对它应该如何工作和命名有不同的看法。 这个怎么样?

更新 -> PATCH(部分更新)
replace -> PUT(替换资源)
create -> POST(创建新资源)

如果您向下滚动更多,您会发现这个关于如何创建自己的方法的示例

var notes = $resource('/notes/:id', null, {
  'update': { method:'PUT' }
});

@jimmywarting - 您的答案是一种解决方法,而不是解决方案。

var notes = $resource('/notes/:id', null, {
  'update': { method:'PUT' }
});

notes.prototype.$save = function() {
    if (this.id) {
        return this.$update();
    } else {
        return this.$create();
    }
};

@jansoren,IMO,您的建议提出了很多难以以通用方式编码的问题。 前任。:

是否可以通过创建和更新操作来扩展 $resource?

  • 保存和创建有什么区别?
  • 似乎不同的后端对用于更新的 HTTP 动词有不同的看法。 我看到使用了 PUT 以及 POST 和 PATCH。

是否也可以覆盖保存操作以在 id 为 null 时调用 create 并在设置 id 时调用 update ?

  • 您将如何识别id

在我看来,您似乎在为不同后端以不同方式处理的事情寻求通用解决方案,因此不确定这里的最佳行动方案是什么。

当 REST 变化如此之大时,我看到了实施 REST 的挑战。也就是说,我希望 AngularJS 团队就他们想要如何解决它提供指导。目前,这些例子似乎很模糊。

对@pkozlowski-opensource 的回应:

  • savecreate之间的区别。 save在创建资源时会 POST,而在更改资源时会 PUT。 create只会使用 POST 并创建资源。
  • 我会在更新整个资源时使用 PUT,而我会使用 PATCH 来更新整个资源的一部分。我想 PATCH 可以很好地与领域驱动设计配合使用。

@shlensky的帮助下,我创建了这个示例:

资源.js

(function () {
    var resource = function ($resource) {
        var resource = {};
        resource.create = function(url) {
            return createResource($resource, url)
        }
        return resource;
    };

    var createResource = function($resource, url) {
        var resource = $resource(url, getParamDefaults(), getActions());
        resource.prototype.$save = function() {
            if (this.id) {
                return this.$update();
            } else {
                return this.$create();
            }
        };
        return resource;
    };

    var getParamDefaults = function() {
        var paramDefaults = {
            id:'<strong i="17">@id</strong>'
        };
        return paramDefaults;
    };

    var getActions = function() {
        var actions = {
            'create': {method:'POST'},
            'update': {method:'PUT'},
            'all':    {method:'GET', isArray:true}
        };
        return actions;
    };

    angular.module('myModule').factory('resource', resource);
}());

信用卡.js

(function () {

    var CreditCard = function (resource) {
        return resource.create('card/:id');
    };

    angular.module('myModule').factory('CreditCard', CreditCard);
}());

myController.js

(function () {
    var myController = function ($scope, CreditCard) {
        // get
        var creditCard = CreditCard.get({id:'abc123'}, function() {
            console.log(creditCard);
        });

        // all
        var creditCards = CreditCard.all(function() {
            console.log(creditCards);

            // update
            var creditCard = creditCards[0];
            creditCard.name = 'changed';
            creditCard.$save(function() {
                console.log(creditCard)
            });
        });

        // create
        var creditCard = new CreditCard();
        creditCard.name = 'new';
        creditCard.$save(function() {
            console.log(creditCard)
        });
    };
    angular.module("myModule").controller("myController", myController);
}());

客户端如何知道它是在创建还是在更新? 它真的不知道。 真的,作为客户端的开发者,你必须清楚自己是需要创建还是更新。

@caitp这是我要问的确切问题:-)

要知道创建/更新之间的区别,我们必须引入某种 ID 表示法,这会使事情进一步复杂化。 并假设如果没有填写 id,则不会保存对象。

@jansoren我认为团队当前的指导很明确: $resource 带有对大多数 RESTful 后端有意义的默认值。 对于场景不太清晰的情况,有自定义/附加方法形式的扩展点。 $resource 是非常可扩展的,坦率地说,基于 $http 构建 $resource 之类的包装器非常容易,因此将所有可能的用例作为 $roesoure 的一部分捕获是没有意义的。

默认情况下,IMO $resource 应该只包含大量后端/场景共有的东西,并留下足够的弹性点,以便人们可以将其扩展到更多“异国情调”的后端/场景(或没有达成共识的情况)。

如果method参数可以是一个函数,那将会很有趣,这样它就可以动态地确定要使用的正确模式。

@caitp - 它在我上面的示例中

 resource.prototype.$save = function() {
            if (this.id) {
                return this.$update();
            } else {
                return this.$create();
            }
        };

@pkozlowski-opensource - 我只是说它仍有改进的潜力。 我觉得奇怪的是 ngResource 文档引用了 wikipedia 声明; PUT 用于更新资源,POST 用于创建资源。 为什么不将 PUT 作为 ngResource 中的标准实现? (回到我最初的问题)
开发人员倾向于接受配置方式,因为它可能更简单。

好吧,PUT 和 POST 之间的对比不在于您是在创建还是在更新,而在于您是在编辑资源还是资源的子资源。 来自RFC 2616

PUT 方法请求将封闭的实体存储在提供的 Request-URI 下。

...相对...

POST 方法用于请求源服务器接受请求中包含的实体作为由 Request-URI 标识的资源的新下级...

对于大多数 RESTful 系统,这最终会被创建和更新,但这不是保证,这就是为什么我非常喜欢 Angular 当前的中性术语save用于 POST,它没有强无论哪种方式的内涵。 我也同意添加一个也调用 POST 的create函数没有帮助,因为正如其他人所指出的那样,它与服务器的通信与save没有区别。

_然而_,我非常喜欢包含 PUT 方法:PUT 根据定义是幂等的(参见上面的第 9.1.2 节),因此请求的多个副本通常应该与单个副本具有相同的结果。 POST 没有这个属性,并且服务器经常会独立解释请求的多个副本并为每个副本创建重复的资源。 在我看来,这足以值得包含,因为在任何“标准”REST 工具箱中都应该至少有一个非重复的编辑路线。

我使用的两个后端 REST 资源实现包括一个 PUT:

另外,那里的数百个路由库几乎都认为 PUT 是一种必不可少的核心方法。

当然,没有它并不是_broken_,但是使用所有默认值然后不得不将我自己的 PUT 添加到我定义的每个$resource感觉很奇怪。

@tdhsmith
我同意你的观点,有一个 PUT 方法会很有趣,我称他为“update”,而 PATCH 将是“partial_update”

我从 DJango REST Framework 中取了这些名称,通用视图有两种方法:

def update(self, request, pk=None):
经过

def partial_update(self, request, pk=None):
经过

我认为后端 REST 的正确实现必须有一个 PUT 方法来执行更新,但我知道不是每个人都实现它。
我当前在 ASP.NET 中的实现没有 PUT 方法,因为由于 c# 是强类型的,因此在后端实现控制流更容易

不过,在任何数据应用程序的 v1 中都需要 PUT 方法似乎很典型,对吧? +1 用于找到一些允许在 Angular 中标准包含这几行代码的约定。

请参阅http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/了解将自定义方法添加到 $resource 的一种非常简洁的方法。

@sjatkins对我来说,这更像是一种解决方法。


我也同意 $resource 应该有一个 PUT 的默认选项,每次需要使用 PUT 更新记录时都必须手动配置它似乎很奇怪,这很常见,IMO。 可以讨论 PATCH 的默认选项,即使它有点不常见,但至少有一个 PUT 是合理的。

此外,人们在问 $save 和 $create 之间有什么区别。 好吧,也许$delete 和$remove 之间的区别相同,即没有? 我认为别名没有问题,即使 ngResource 已经有了。

资源应该是基于 Rest 的,所以为什么它不只包含 http restful 路由......

例子:

{
    'get':    {method:'GET'},
    'post':   {method:'POST'},
    'update': {method:'PUT'},
    'query':  {method:'GET', isArray:true},
    'delete': {method:'DELETE'}
};

因为不同的后端对应该使用的动词有不同的看法。
$resource提供了一个通用的解决方案并且易于扩展。

基本上,您可以使用$resourceProvider.defaults.actions设置默认操作。
不知道留下这个无证是故意的还是只是疏忽。

好吧,我会再给资源一个机会。 我喜欢可扩展的组件!

文档已更新,包含有关默认操作的更清晰信息。 如果需要,这应该允许轻松配置 PUT。

此页面是否有帮助?
0 / 5 - 0 等级