使用不同的 URL 进行 POST 以创建模型的 Backbone 方法是什么?

What is the Backbone way to use a different URL for POSTing to create a model?

我们已经构建了一个 RESTful API 与 URL 类似

/api/v1/cars/
/api/v1/cars/34

所有这些端点照常接受 GETPUTPOSTDELETE 方法。

为了帮助您理解我们的模型:这些汽车的 engine/wheels/specifications/etc 通常作为调整过程的一部分进行修改。

因此,我们在汽车上有了 'report' 的概念:在汽车上执行并存储以供日后查看的各种测试结果的集合(就像您的机械师可能会生成一份报告你的车供以后比较)。

这些报告存储在URLs like

/api/v1/car_reports/
/api/v1/car_reports/76

我们选择不允许这些端点接受POST方法,你只能GETDELETE他们([=18=没有意义] 因为这些报告在创建后永远不应修改)。

我们决定您通过汽车本身的 URL 创建汽车报告:

  1. POST 到像 /api/v1/cars/34/make_report 这样的端点,并带有你希望 运行 的测试列表作为此请求中的正文数据,
  2. 后端使用汽车的详细信息和测试列表生成报告,并将其存储在 URL 中,例如 /api/v1/car_reports/77
  3. 后端通过在响应中向客户端发送位置 /api/v1/car_reports/77 来结束(我们决定,作为 formality/convenience,实际上将报告的副本包含在响应)。

我们的前端使用 Backbone.ModelBackbone.Collection 使用此 API,例如:

var Car = Backbone.Model.extend();

var CarCollection = Backbone.Collection.extend({
    model: Car,
    url: '/api/v1/cars'
});

var CarReport = Backbone.Model.extend();

car CarReportCollection = Backbone.Collection.extend({
    model: CarReport,
    url: '/api/v1/car_reports'
});

我们可以通过 CarCollection:

轻松创建 Car
var car_collection = new CarCollection();
var car = car_collection.create({
    make: 'Ford',
    engine_size: 1600,
    tyres: 'Michelin'
});
// Suppose that car.id = 34

在那辆车上创建 CarReport 的最佳方法是什么? 目前我正在做一个显式的 ajax 调用,例如:

var tests = {
    'maximum speed',
    'miles per gallon'
};
$.ajax({
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(tests),
    url: car_collection.url + '/' + car.id + '/make_report'
});

这感觉像是黑客攻击。

我怎样才能以更 Backbone-ish 的方式做到这一点?

非常感谢。

在你的位置,我可能会拥有一个单独的模型(有点像工厂?)来创建报告,另一个模型用于 GETDELETE。这会给最 Backbone-ish 恕我直言的感觉。

Here 是如何确保不犯错误的示例。

在REST中,我觉得有以下几点:

We made the decision that you create a car report via the URL of the car itself:

  1. you POST to an endpoint like /api/v1/cars/34/make_report, with a list of the tests you wish to run as the body data in this request,

是禁忌。
端点旨在表示 资源 ,REST 动词(即 GET、POST、PUT 和 DELETE)是对资源执行的唯一操作。
因此,您定义的 make_request 方法宁愿表述为:

POST /api/v1/cars/34/reports

这是我对其余问题的两分钱:

当您这样定义 URL 时:

/api/v1/car_reports/77

这没有错,但我觉得下面的表述更清晰:

/api/v1/cars/reports/:id

以这种方式构建 url 更符合习惯。如果明天你也有摩托车,你将有:

/api/v1/cars/reports/:id
/api/v1/motorcycles/reports/:id

您的问题:

What is the best way to create a CarReport on that car? At the moment I am doing an explicit ajax call like:

您分享的示例直接使用jQuery ajax。 Backbone 也依赖于此方法来执行对服务器的 ajax 调用,但其理念有点不同。 Backbone 模型的目的是表示单个资源单元,而 Backbone 集合表示单元集合。因此,如果你想 POST 一个模型到服务器,你最好在将其属性设置为 POSTed 之后直接在模型上调用 save(),如果你想遵循模型代表资源单元的哲学。

但是,在您的示例中,报告并未 'actually' 直接绑定到汽车,因为它绑定到在汽车上执行的测试。所以我建议有这样的东西:

/api/v1/cars/77/tests/reports

原因是,测试存储在数据库 table(多对多)中,其中测试数据与汽车相关联。因此 "tests" 成为特定汽车子集的资源,数据可以作为 restful 路线发送到其中(我想理论上您可以在同一辆车上执行多个测试,这将使系统更加灵活)。
而不是在 url 中定义 make_report,它可以是在发布或更新测试数据时调用的方法(使用 v1、v2 等生成报告)。

进一步思考,如果您假设您明天可能会有其他车辆,例如摩托车,您可能会将测试作为资源以及车辆作为子集,这也是有道理的:

/api/v1/tests/cars
/api/v1/tests/motorcycles

最后,所有这些选项都是可能的。因此,REST 并没有真正定义为一门精确的科学,而是一种架构风格;如果您在后端正确实施它,它仍然可以工作。所以我想你选择什么取决于什么对你和你的具体情况最有意义。

我的两分钱,我希望它能对进一步的选择提供一些见解。