在RESTful服务中超越CRUD

5
我正在开发一个 WCF RESTful 服务,注意到在某些地方,我可以用多种方式表示非 CRUD 操作(而不是资源)。
比如说,我们购买了一台新的电视,并将其连接到我们的私人网络。现在,我们想要构建一个 Web 服务来查看和控制这台电视。
  • 读取和更新电视属性我们将使用以下URI:

    http://domain/tv/ GET | PUT - 获取和更新电视属性。 (company, owner, inches)

  • 观看视频我们将使用以下URI:

    ws://domain/tv/video - (假设WebSocket是传输视频内容的最佳选项)

  • 操作:

    • updateVersion
    • startBIT (内置自检)
    • changeChannel
    • turnVolumeUp, turnVolumeDown

第一种设计是使用属性来表示操作。服务器将注意到属性更改,然后执行所需的操作。最后POST无法用属性表示的操作:

http://domain/tv/ GET | PUT - 通过JSON对象获取或设置 音量频道

对于 updateVersionstartBIT

http://domain/tv/ POST 并加上 {function: 'updateVersion'} 或 {function: 'startBIT'}

第二种设计是使用Command资源表示所有操作:

http://domain/tv/commands POST 并加上 {command: 'BIT', sender: 'Dan' ... } - 创建新的命令以执行 startBITchangeChannelturnVolume

第三种设计是将可作为名词发音的每个操作表示为资源,其余操作表示为属性:

http://domain/tv/versionUpdates 获取 | 更新 | 删除 | 提交

http://domain/tv/BITs 获取 | 更新 | 删除 | 提交

http://domain/tv/ 更新 ({volume: 10})

http://domain/tv/ 更新 ({channel: 29})

什么是最佳的RESTful设计?


@David,我可以要一个音量吗?并不是所有的东西都适用于REST,RPC就是其中之一。 - CodeCaster
@David,POST tv/volume/100 的实际含义是什么,考虑到 POST 的语义?PUT tv/channel/13 可能意味着您想要更新第 13 个频道的频率或描述,但并不意味着电视机应该切换到该频道。为什么要使用两个不同的动词来设置两个不同事物的当前状态,这两个事物在同一时间自然只能有一个处于活动状态 - 除非在频道的情况下有多个调谐器? - CodeCaster
@DavidBrabant 这看起来不太符合RESTful的标准,因为当引用blah/volume/100时,它看起来像我们在使用动词,而RESTful的方式是使用名词。你的建议看起来与blah/changeChannelTo/23非常相似。 - Matan Givoni
@Matan. 嗯?"Volume" 是一个动词吗? - David Brabant
1
不,不是这样的,但是看看当我把 volume 替换为 changeVolumeTo 时会发生什么,你明白我的意思吗?如果我们向 blah/changeVolumeTo/10 发送 POST 请求,那意味着我们设计得很糟糕。 - Matan Givoni
显示剩余2条评论
1个回答

3
第三个选项(以下修改)看起来是最好设计的——因为REST是关于资源和名词,而不是关于动词和操作。
我会做出以下更改:
- `http://domain/tv/firmware GET | DELETE | POST` 我会将`versionUpdates`更改为`firmware`——这似乎更加自描述。而且,这里似乎`PUT`操作没有任何意义——你可能事先不知道新的固件版本。因此,`GET`返回当前固件版本,`DELETE`删除最新版本并恢复上一个版本,`POST`查找并安装最新版本。
- `http://domain/tv/BITs GET | POST` 在这里,似乎只需要`GET`和`POST`就足够了。您只需要`GET`所有测试的结果或特定测试的结果,或者只需`POST`新的测试即可。
- `http://domain/tv/ PATCH ({volume: 10})` 和 `http://domain/tv/ PATCH ({channel: 29})` 由于两者非常相似——我会将`PUT`更改为`PATCH`——请记住,在使用`PUT`时,您需要包括整个对象,即每个属性。`PUT`也是幂等操作。而在使用`PATCH`时,您可以更改单个属性。

你对第二个选项(Commands)有什么看法?使用“Commands”时,我们封装了常见的电视操作(尽管它似乎是将所有操作都视为单个名词的技巧,过于通用..)。我同意你的观点,尽可能多地使用名词(固件和BITs)。 - Matan Givoni
1
我认为命令只是操作的包装器。我认为将函数视为资源有点尴尬,特别是它不会被保留在服务器端而是被调用;) 命令可能对于远程控制很有用(如果您需要对其进行建模)-但不是作为函数而是资源。我理解使用REST对于建模现实世界有时非常困难,但我们应该尽可能遵守一般规则。 - Opal
是的,但你如何以RESTful的方式调用一个函数? - Opal
是的,我意识到调用函数需要以RESTful的方式进行,因此例如将新卷放置在http://domain/tv/中是更符合RESTful标准的。 - Matan Givoni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接