RESTful 有用吗? HTTP 有 GET POST 就足够了?

2017-02-15 12:59:26 +08:00
 noli

不少程序员都是这么认为的,基于 HTTP API 的服务,只要用 GET 请求和 POST 请求就足够了。 像 RESTful 这样的 大量使用 PUT , DELETE 请求是不必要的。

真的吗,我来举一个例子。

假设有一类资源 ResourceXYZ ,对其有增删查改的操作。 如果只使用 GET POST 之类的设计方式,那么很可能会设计以下的请求接口:

POST .../addResourceXYZ
POST .../delResourceXYZ
GET .../getResourceXYZ?resourceId=resourceId
POST .../updateResourceXYZ

如果按照 RESTful 的 设计方式,很可能会设计以下的请求接口

POST .../ResourceXYZs
DELETE .../ResourceXYZ/{resourceId}
GET .../ResourceXYZ/{resourceId}
PUT .../ResourceXYZ/{resourceId}

现在假设,客户端要获取该资源,其 ID 为 resourceId 。 如果成功,那么一切都好说。 如果失败, Restful 的处理方式是,通过 HTTP status 返回错误码来表示原因,例如 404 表示该资源不存在。

那么只用 GET POST 两种方法的方式呢? 响应请求

GET .../getResourceXYZ?resourceId=resourceId

的时候能不能也用 404 呢?

按照 404 的语义,响应 404 是不对的: 因为客户端请求的 URL 实际上是正确的,只是对应的参数没有找到对应的结果 很多时候,就只能靠响应 200 然后返回空数据或者空对象来处理了。 例如 Content-type 为 application/json 时,可以返回 {} 或者

{
    "error": "not found",
    "code": 404
}

这样就会要求客户端,必须处理 HTTP 回复的具体内容,而不能只处理头部。 那么客户端要怎么处理这个 json 呢 要先解析 json ,然后尝试分别这是一个资源的内容,还是一个错误提示。

对于强类型语言例如 C/C++ OC Swift 写的客户端来说,恐怕就忍不住要问候服务端程序员一家了。

更重要的是……

没有库会支持这种拍脑袋式的设计。

全文完,欢迎拍砖。

40929 次点击
所在节点    程序员
207 条回复
noli
2017-02-15 13:56:48 +08:00
@gamexg

如果不需要解析错误信息呢? RESTful 能够照顾到两种需求。
如果直接返回 200 做不到这一点。
magict4
2017-02-15 14:05:20 +08:00
@noli 我不会这么设计我的 API 的。 Messages 这个概念,是因为 Restful 只提供了 4 个动词的一种变通。我的 Server 可能通过 Message Queue 来实现消息的传递,但这种底层的东西不应该暴露给我的客户。我需要暴露给客户的,应该是类似 send email, archive email, move email 之类的接口东西,然而这并不能通过 Restulful 来直接实现。你可参考下 AWS 的服务文档
Felldeadbird
2017-02-15 14:08:59 +08:00
我个人认为 GPPD 最重要的优点在于 统一了 URL 操作,节省了起名的困难。
例如:现在 CURD 都是 /article/1.html 。 我都不用去想起他动作了。
换以前,/article/1.html , /addarticle/1.html, /updatearticle/1, /removearticle/1..
murmur
2017-02-15 14:11:43 +08:00
以现在的框架 restful 更多成为一种形式或者信仰 除了 json 发出和 json 结果比较讨人喜欢 其余的没啥问题
比如 /api/removeItem 和 /api/item 发 del 有什么区别么?前者如果命名一致文档合理同样是优秀设计
noli
2017-02-15 14:12:25 +08:00
@magict4

我说的 Messages 是类似于论坛消息之类的业务 Message , Email 概念的泛化、抽象化。
你当然可以不用 Restful 来实现,而且我本人也不建议。
你要我举个例子,那我就免为其难了。

事实上,我认为,操作系统的全部 系统调用,都可以用 RESTful API 来对应表示。
不习惯的人可能会觉得别扭,但是是可行的、科学的、经得起考验的。
noli
2017-02-15 14:13:28 +08:00
@murmur

"比如 /api/removeItem 和 /api/item 发 del 有什么区别么?"

见 #15
wshcdr
2017-02-15 14:14:07 +08:00
我认为采用 restful 的话, 客户端(包括移动端)是要自己维护自己的业务接口的,服务端只是暴露 GET/PUT/DELETE/POST 分别对应增删查改

对应发邮件的例子,也就是客户端要自己实现发送这种功能,自己在发送功能里协调对 GET/PUT/DELETE/POST 的调用。
mcfog
2017-02-15 14:17:46 +08:00
1. restful 是风格不是规范
2. 如果楼主如果真心认为“ POST /updateXYZ?id={id}”和“ PUT /XYZ/{id}”对等,那我觉得并不能说是真正理解了 restful
3. 正如其他很多同学说的, restful 的状态码数量有限,用于表示复杂的业务问题经常不够,基本最终还是要在 body 里定义自己的错误描述体系
4. restful ,状态, cookie , session 之间的关系我一直没找到权威说明。业界常见的 restful 风格接口大多用非 cookie 的令牌 token+服务端 session 来处理状态,此时接口连基本的在 web 端和 app 复用都得讨论了( token 让 js 自己存储和 secure httpOnly 的 cookie 的安全性差距)欢迎指教
5. 把接口分两大块:
a) 业务接口( app/web 等使用的),这类接口我倾向全 POST 或幂等读 GET 其他 POST ,返回结构统一 code,message,body 的风格, HTTP 状态码用来表述“通信状态”, body 内返回吗表述“业务状态”
b) 后端接口( CGI 端再调其他 server 用的),这类接口如果业务逻辑量小,贴近“资源 CRUD ”的 restful 最贴切的领域的话,我会考虑 restful 作为备选方案
magict4
2017-02-15 14:22:17 +08:00
@noli 你看看我有没有误解你的意思。拿『移动到文件夹 X 』举例。

如果是事务的,我猜你对应的 URL 会是
post .../MoveEmailTransaction

如果不是事务的,你说会用两个 HTTP request 来实现,那对应的 URL 肯定跟上面的会有所不同。

如果我的理解是对的话,同样的一件事情,因为实现不同,对应的接口变了。在我看来,好的 API 设计应该是无论实现怎样, API 应该保持稳定。所以我会用
post .../moveEmail?source=???&&destination=???

> 但是是可行的、科学的、经得起考验的
如果因为实现的不同,需要改变 API 的设计,我不太能认同是科学的。

我的主要观点是, Restuful 提供的 4 个动词是远远不够的。在复杂的业务场景里面,如果想用这 4 个动词来表示所有操作,往往会让 API 的设计变的更加困难。
baiyi
2017-02-15 14:22:35 +08:00
RESTful 说到底也只是众多 Api 规范 中的其中之一, 它是有一定的适用性的.

在 RESTful 适用性之外的项目,就不要强行上 RESTful 了

现在 Api 的规范都和语言之争一样火爆了......
baiyi
2017-02-15 14:24:05 +08:00
@baiyi 口误,RESTful 是设计风格不是设计规范
otakustay
2017-02-15 14:34:31 +08:00
restful 是架构风格,不是接口设计风格,如果你做不到 restful 架构,请不要在接口这么个东西上盲目追求 restful
gevin
2017-02-15 14:37:52 +08:00
又想提一下我原来写的两篇博客:

RESTful 架构风格概述: http://blog.igevin.info/posts/restful-architecture-in-general/
RESTful API 编写指南: http://blog.igevin.info/posts/restful-api-get-started-to-write/
noli
2017-02-15 14:41:37 +08:00
@magict4

在一个 openstack 相关的业务里面,我用 RESTful 实现过对 AD ( ActiveDirectory )相关的接口 WEB 封装。
里面也是经常有对各种简单的、原子的 对各种 AD 条目的操作的 组合所形成的事务。
提交事务方法只有一种:
```
POST .../Transaction
```
然后在请求体里面用 JSON 描述这个事务的各种操作和参数,例如:

```
{
[
{"method": "POST", "resource": "/someResources", "args": {...} },
{"method": "DELETE", "resource": "/someResource/1234"},
]
}
```
实际上就是把一连串的 RESTful API 调用转化成一个 JSON 对象来描述要执行的事务。

所以你说“同样的一件事情,因为实现不同,对应的接口变了” 实际上不存在~ :)
zweite
2017-02-15 14:47:31 +08:00
想象当 Restful 遇到爬虫会怎么样
msg7086
2017-02-15 14:50:06 +08:00
为了去套 RESTful 而强行把不是资源或者不适合以资源形式访问的东西也当做资源,就是个问题了。
这有点像数据库的范式,你可以把范式堆得老高,但是实际开发中没人会真的这么干,意思意思做得干净点就行了。
顺便提一句,很多实现里(比如浏览器), HTTP 动词是只支持 GET/POST 的, PUT/DELETE 都要用 _method=? 之类的来传递,然后在上层去抽象。
baiyi
2017-02-15 14:50:08 +08:00
@zweite RESTful 跟爬虫关系不大, 因为他返回较为完整的 http 信息,或许对爬虫更加友好
whx20202
2017-02-15 14:51:58 +08:00
@otakustay 我一直以为是接口设计风格。

给你这么一说我才反应过来 肯定有很多接口看起来 restful 实际后端架构并不是
baiyi
2017-02-15 14:52:04 +08:00
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
这篇文章是我看来关于 Api 中 RESTful 的实践 中最好的一篇文章了

想要更深的了解 REST,可以去找找博士的论文读
wizardoz
2017-02-15 14:55:43 +08:00
非要说够不够的,那我说一个 POST 就够了,还要 GET 干啥?
所以我们要的不是够,我们要的是优雅。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/340607

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX