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 写的客户端来说,恐怕就忍不住要问候服务端程序员一家了。

更重要的是……

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

全文完,欢迎拍砖。

42295 次点击
所在节点    程序员
207 条回复
magict4
2017-02-16 05:22:20 +08:00
@lightening 我暂时还没开看你贴的视频,有时间的话会看。

如果我没有理解错,你跟楼主的意思应该都是

sendEmail 对应的是 createDelivery
moveEmail 对应的是 createTransaction

之所以会有这样的对应,是因为 Restuful 只提供了 4 个动词。有了这样的限制,我们不得不对资源名字进行变换,把 email 变成 delivery 和 transaction 。

我同意你说的,我们总是可以想办法把 API fit 进 Rest 这个框架 /风格。但是我不能认同我们应该这样做。
TigerS
2017-02-16 06:55:05 +08:00
小网站感觉完全够用,但是如果稍微大点就不太方便。

例如 DigitalOcean API ,我们自己写一个小的管理的时候基本上是
```
api_url: 'https://api.digitalocean.com/v2/'
def action(action, droplet_id):
blah_blah(api_url + 'droplet_id' + action)
```
只是举例,随便写了点

很多东西都可以调用,而且简单易懂,而且很多可以重复利用

但是如果全是 post 的话,就需要不断确认是 post 到了哪里,虽说也可以,但是有时候并不好用。
baconrad
2017-02-16 10:46:57 +08:00
以前端來看,今天我使用

`GET .../ResourceXYZ/{resourceId}`

結果 server 回傳 HTTP status 404

請問以下哪個原因才是正確的?

1. client 端網路環境出問題。
2. server 端網路環境出問題。
3. url 輸入錯誤。
4. 我要求的資源不存在。
ShiningRay
2017-02-16 10:47:26 +08:00
你说的是以 RPC 的风格来设计 API
另外楼主肯定用了很麻烦的对 restful 不友好的框架
mqtt
2017-02-16 11:46:07 +08:00
POST .../addResourceXYZ
POST .../delResourceXYZ
GET .../getResourceXYZ?resourceId=resourceId
POST .../updateResourceXYZ

这样的命名我是无法接受的,又长又丑。
资源不存在, 本来就应该提示 404 啊, 表明用户访问的资源未找到,这样客户端就可以通过 response code 知道自己请求的资源不存在。
mqtt
2017-02-16 11:46:46 +08:00
response status
changwei
2017-02-16 11:50:25 +08:00
这种争论可以直接参考大公司的最佳实践。

你们去看一下大公司的 app 接口就知道了,像百度腾讯的 app 接口都只有 get 和 post ,然后返回的 json 里面有专门的错误码,错误消息解释和消息体。
baiyi
2017-02-16 12:33:02 +08:00
@changwei github 大吗
baiyi
2017-02-16 12:34:12 +08:00
@changwei github 不光有 RESTful 的, 还有 GraphQL 的
国内的公司没有, 只能说明他们不去接触新东西,或业务不合适,代表不了其他的什么
jybox
2017-02-16 12:43:17 +08:00
其实我的想法和楼主差不多(两年多以前我也在 V2EX 发过类似的帖子),即我是觉得 RESTful 并不能覆盖到所有的情况,硬要把不适合的业务对应到「资源」是个费力不讨好的事情。但确实如果能够顺着 RESTful 的思路的话,会有一些比较方便的工具可用,所以也没有必要非要「不遵守」 RESTful 。所以我觉得在做 API 设计的时候,最重要的是项目本身能够统一和自恰,适合 RESTful 的部分就用,不适合的情况也没必要硬往上靠。

RESTful 和 HTTP 本身的关系并没有那么密切,关于如何设计基于 HTTP 的 API 实际上不止 RESTful 一个方案。
loading
2017-02-16 12:44:07 +08:00
只是参考,用 get,put,post,dekete 对于我来说就是可以少写几个路由。
noli
2017-02-16 13:53:22 +08:00
@baconrad

1 和 2 是不可能的因为服务器已经返回 404 了所以肯定网络没有问题

3 和 4 都有可能
noli
2017-02-16 13:56:55 +08:00
@ShiningRay

猜错了,第一版后端是我写的, restful 很爽。现在我主攻客户端,后端业务升级给了另外一个人,所以我才会集中吐槽不用 restful 会给客户端带来多大的麻烦?
wizardforcel
2017-02-16 14:08:16 +08:00
动态路由不等于 REST ,非 REST 也可以用动态路由 GET /ResourceXYZ/{resourceId}。

别什么都往 REST 上套。
TangMonk
2017-02-16 14:11:34 +08:00
@Reign GET 可以 cache 。。
wizardforcel
2017-02-16 14:16:07 +08:00
以及。。很多 http 客户端库不支持除了 get 和 post 之外的方法,遇到这种情况我真是。。。

另外不用 REST 照样也可以设计出来优雅的路由

增: POST /ResourceXYZ/create
删: GET /ResourceXYZ/{resourceId}/delete
改: POST /ResourceXYZ/update
查: GET /ResourceXYZ/{resourceId}
noli
2017-02-16 14:29:18 +08:00
@magict4

我觉得设计 restful api 的时候很重要的一点是,要弄清楚业务理念哪些概念是原子性的,哪些操作是可以通过多个对原子性概念的操作组合出来的。

如果你觉得让客户端来做这些原子性动作组合,是要求太高,那么你可以加一层 api 来接收客户端的意图,然后在这层 api 之下实现业务,

这样通常能解决很多所谓 fit 进 restful 的问题
wizardforcel
2017-02-16 14:30:09 +08:00
@noli

> 又说请求的东西不是资源,什么东西不能视作资源来被管理呢?除了无限的东西之外。

如果不用 REST ,某些 API 我就可以设计成

/login
/reg
/tranfer

用了 REST 就没有这些简明扼要的设计,这是不是增加复杂度呢??
wizardforcel
2017-02-16 14:33:27 +08:00
@noli

> 如果你觉得让客户端来做这些原子性动作组合,是要求太高,那么你可以加一层 api 来接收客户端的意图,然后在这层 api 之下实现业务,

客户端做原子性动作组合存在安全隐患。

服务端里增加一层 API 嘛。。为什么我要在 HTTP API 里面调用 HTTP API ,而不是直接调用 DAO 或者 ORM 呢??没你这么抽象的。 HTTP API 就不是给服务端自己调用的,这样粒度比 DAO 大多了。
noli
2017-02-16 14:44:59 +08:00
@wizardforcel

/login /reg /transfer
你能用这种方式设计这些 api ,恰好说明了你的业务不需要把这些行为视作资源。
如果你需要满足这些需求的时候,你就自然要用 restful 了

1. 查询某用户在某时段内的 login 记录
2. 针对某些注册申请进行人工审核,或者拒绝或者 forward
3. transfer 是异步的,需要实时关注 transfer 是否完成

你没有这些需求,你当然不需要把这些视作资源。

关于“为什么要在 HTTP API 里面调用 HTTP API ”
没有为什么,我不关心实现,因为这只是为了适应低能的客户端,怎么实现是业务需要问题。
至于为什么 HTTP API 调用 HTTP API ,那是因为 do not repeat your self. 当这些被调用的 更底层 API 实现有变动的时候,你不需要改高层 API 的实现,虽然这也不一定是必须的。
你连这个道理都不懂,我感觉我们的层次有差距啊。

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

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

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

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

© 2021 V2EX