如何在REST API中设计复杂的更新操作

时间:2014-07-29 11:49:48

标签: rest symfony

我目前正在开发REST API,尝试尽可能使用最佳实践进行设计。

我使用Symfony2 PHP框架但我的一些问题对任何REST API都有效。我猜。

从特定资源的基础设计开始:

GET        /resource            - Get all resources
POST       /resource            - Create resource
GET        /resource/{id}       - Get resource with id={id}
PUT|PATCH  /resource/{id}       - Edit the resource with id={id}
DELETE     /resource/{id}       - Delete the resource with id={id}

假设我的资源在更新时具有复杂的规则。

  1. 它有一个“状态”字段(例如一个浮点数),只能按照特定方案进行更新
  2. 它有一个“日程安排”字段(日期时间),有不同的选择,并不总是相同
  3. 我应该如何向API使用者公开这些规则?对于日程字段,我该如何提供当前可用的不同选择?


    关于Symfony服务器端部分,我遵循了本演练的大部分建议:http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/

    我的帖子,PUT& PATCH操作由Symfony Forms处理,因此大多数规则都由Symfony约束/验证功能处理。

    但表单绑定非常有限,如果用户将状态字段从 2 更改为 3 ?最好的方法是什么?

    提前致谢。

3 个答案:

答案 0 :(得分:1)

HTTP有另一个你没有使用的动词:OPTIONS。您可以使用它来列出计划选项。

以下是关于它的博客文章:http://zacstewart.com/2012/04/14/http-options-method.html

至于更新状态,我会重复POST并在字段中包含action。例如:

POST
{
    "type": "update",
    "status": 3
}

修改后的REST:

GET        /resource            - Get all resources
POST       /resource            - Create resource
GET        /resource/{id}       - Get resource with id={id}
PUT|PATCH  /resource/{id}       - Edit the resource with id={id}
DELETE     /resource/{id}       - Delete the resource with id={id}
OPTIONS    /resource/{id}       - Retrieve options of resource with id={id}

请记住,除了GET之外,您可以在身体中传递参数,并且您可以在URL中传递任何参数以获取GET。

答案 1 :(得分:0)

我对Symfony2没有任何了解,因此我将专注于更通用的REST如何解决暴露规则问题。

  • 为REST API的使用者提供文档。这是他们在实际使用你的API之前首先要做的事情。使用工具,从自动生成的帮助页面到第三方提供商,如Apiary.io或类似。

  • 当消费者发送“错误”请求时创建有意义的响应:当请求参数丢失或无效时,使用正确的http响应状态代码(错误请求,冲突等)。 如果放松了REST api,它还可以包含有关出错的信息以及如何在响应正文中解决问题。 过去对我有用的是拥有一个通用的ErrorMessage实体,该实体在每个未成功的请求时返回,包含标题,错误描述和专用的更具技术性的“dev-description”,可以启用/禁用在服务器端测试/生产。 就我而言,我的消费者都知道,如果成功,他们可以获得预期的响应实体,或者如果失败,他们可以获得响应中的通用ErrorMessage实体。

  • 如果您能够遵守规则,为什么不将这些规则作为您服务的元信息提供?例如。在我的情况下,我知道我有一组参数,每个参数都有一组可用的选项。将参数视为查询字符串中的键,将选项视为该键的值。在复杂的世界中,参数选项取决于其他参数选项,例如。在我的例子中,参数B的可用选项取决于参数A的“选择”选项。我可以通过在我的REST api中提供“元数据”资源来公开这些依赖关系,例如。一个JSON结构,列出了这些参数的所有参数和所有选项,并为每个选项添加了一个“需求”部分,如果参数xy选择了选项p和q,那么该选项只能“可用”。 这允许我的消费者 - 通过对该元数据资源的单个请求 - 在客户端创建“状态机”。我希望你能得到这张照片。

答案 2 :(得分:0)

以下是我对REST的理解 - 处理更新并向API客户端发布更新操作的完整方法。

这是基于this精彩的书籍和Fowler's有关REST的文章,其中包含File Levels of Media Type的一些内容和有关Restfull CQRS的文章。基本上你使用PUT进行更新并通过内容类型传递操作,并通过mediamedia在超媒体控件中宣传内容类型。

所有可用于资源当前状态的操作都列在超媒体控件中,这些控件通过这样的资源表示传递:

<myresource>
  <status>ACTIVE</status>
  <some-field with-attribute="value"/>
  <some-other-field/>
  <!-- other fields representing state of resource -->

  <link rel = "self"
    uri = "/resource/1234"/>
  <link rel = "/linkrels/resource/changeStatus"
    uri = "/resource/1234"
    mediaType = "application/vnd.myapp+xml;domain-model=ChangeStatusCommand"/>
  <link rel = "/linkrels/resource/changeSchedule"
    uri = "/resource/1234"
    mediaType = "application/vnd.myapp+xml;domain-model=ChangeScheduleCommand"/>
  <link rel = "/linkrels/help"
    uri = "/help/resource"/>
</myresource>

与mediaType的链接提供了足够的信息,允许使用哪些命令。在许多情况下,这应该是非常特定于当前资源状态的东西。例如,如果您可以将其从状态ACTIVE移至TRASHED,则命令不应命名为StatusChange,而应命名为TrashCommand,依此类推。