若你曾写过 REST API,你确定体验过那些无休止的争论,例如该使用哪一个动词?该使用哪一个 HTTP 状态码?该如何组织个人 URL?这些都没有正确答案。不是全部的操做都能由某个动词表示。不是全部的错误都匹配 HTTP 错误。为什么咱们要在 API 上使用那些为超文本设计的动词和错误码?咱们使用 HTTP 做为客户端/服务端的通讯方式是由于它是如此广泛,在它上面增长 REST 多是杀鸡用牛刀了,特别当你只是想要一个简单的 API 接口。web
思考这个典型的 API 在其余语言中的调用以及它是如何转化为 REST。数据库
OrderDTO Customer::GetOrder(int customerID, int orderID)
做为一个 REST 调用应该相似这样编程
GET /customer/33245/order/8769
若是咱们将方法名置于变量之间,那么问题就来了,该 URL 的哪部分是终点?哪些是参数?这些参数又与什么对应?很难仅仅经过 URL 推断出它是如何传递给后端的。后端
一个简单的 API,与咱们原始的方法调用很像,没有混淆参数名称,而且清晰定义了要传递的参数数组
GET /customer/getOrder?customerID=33245&orderID=8769
做为一位 API 用户或是设计师,上面的 URL 更容易被理解,由于方法调用和参数被清晰的分离开来。这并非 RESTful,可是除此以外在编程中哪里还用过如此相似 REST 的模式?有语言强制要求使用 4 个动词来修饰吗?这些真的必要吗?简单的说,这不是必要的。POST 解决一切。服务器
REST URL 看起来『更干净』,但它们更容易被理解吗?SEO 不是必要的。当你但愿扩展更多参数,或使用更加复杂的参数例如数组,这些『简单』的 URL 会让你很头疼。app
GET /customer/33245/order/8769
为什么不把参数从 URL 中移除?将它们放在 query string,或以 JSON 格式 POST 过去。这样子参数被显示命名,更易理解,消除了对复杂路由属性的依赖。post
POST /customer/getOrder { customerID: 33245, orderID: 8769 }
为什么要用为接收超文本而设计的数量有限的错误码来表示你的错误响应?测试
保存来自服务器自身错误的 HTTP 特定错误码。例如你获得一个 404 响应,那么它来自服务器仍是你的应用程序?一个简化的 API 可能在成功时返回 HTTP 200 ,在遇到错误时返回 500 和应用级错误码。设计
这些代码能够是为业务定制的(订单未找到,摄像头未找到,数据库跪了,已打包等等)。代码能够是惟一以方便追溯。测试中结合特定应用错误码能够提升测试准确性。
POST /shipment/cancel { orderID: 567, reason: ‘Wrong size’ } 400 Response { appError: 1023, message: ‘Order already shipped’, showUser: true }
若是你以为 HTTP 响应应该是 500 而不是 400,那么这只是这篇文章的部分观点。关于怎么作是『对』的争论一直存在。
REST 和 RESTful 之间的一个核心区别在于 HATEOAS 的实现。通常是在你的 API 请求响应中发送相关 API 的 URL。若是你的 API 以一个银行的存款响应了,它也包含用来取钱的 URL。这种方式下 API 是可发现和可遍历的。在其余语言中 API 调用不返回方法指针指向相关的方法。因此又一次发问,为什么咱们将 API 搞得如此复杂?仅仅由于咱们咱们经过 HTTP 来执行它们仍是为了适应别人的学说?
另外一个常常实现不少魔法的地方就是 API 版本控制方案。若是一个单一方法须要版本控制那么它能够简单的以 /user/getProfile2
形式实现,为什么要用其余不直接的方法?若是控制器入口须要控制版本,能够简单的相似于 /user2/getProfile
。难道须要任何更复杂的东西吗?没有特殊的路由,没有魔法而且直接映射到你的后端控制器和方法。
一个 URL 应该清晰定义了位置,终点和参数。无需复杂的路由代码来分离参数。或是经过动词区分意图。
动词无关性,HTTP 动词真的只应该用来识别参数的去向 - 对 GET 来讲它在 query string,对于 POST 它在 body。
版本控制应具体到被修改的事物。向下兼容易于维护,无需特殊的映射或属性。
HTTP 错误码,简化为 200/400。response body 包含应用特定错误码和消息。
具象状态传输,例如
GET /user/getProfile
可能返回一个 ProfileDTO (具象状态) 能被更新和做为一个参数经过下面的 API 回传至服务器
POST /user/setProfile
没有人在正确的 URL,动词或状态码上达成一致意见。REST 是一种风格,而不是一种标准。在远程 web 服务器上调用方法应该是一个简单的 RPC。 方法名称不和参数混合。方法不用动词修饰。参数都在一个单独的地方。简单。
原文:who-cares-about-get-vs-post-norest by swax
做者:swax