REST API - 为什么要使用PUT DELETE POST GET?

Sta*_*ann 151 php api rest json soap

所以,我正在浏览一些关于创建REST API的文章.其中一些建议使用所有类型的HTTP请求:比如PUT DELETE POST GET.我们将创建例如index.php并以这种方式编写API:

$method = $_SERVER['REQUEST_METHOD'];
$request = split("/", substr(@$_SERVER['PATH_INFO'], 1));

switch ($method) {
  case 'PUT':
    ....some put action.... 
    break;
  case 'POST':
    ....some post action.... 
    break;
  case 'GET':
    ....some get action.... 
    break;
  case 'DELETE':
    ....some delete action.... 
    break;
}
Run Code Online (Sandbox Code Playgroud)

好的,授予 - 我对Web服务还不太了解(还).但是,通过常规或(包含方法名称和所有参数)接受JSON对象并不是更容易,然后也以JSON响应.我们可以通过PHP轻松地序列化/反序列化,并且可以使用该数据执行任何操作,而无需处理不同的HTTP请求方法.POSTGETjson_encode()json_decode()

我错过了什么吗?

更新1:

好的 - 在深入研究各种API并学习了很多关于XML-RPC,JSON-RPC,SOAP,REST后,我得出结论,这种类型的API是合理的.实际上堆栈交换几乎在他们的站点上使用这种方法,我认为这些人知道他们正在做什么Stack Exchange API.

zzz*_*Bov 198

RE表示S tate T传输的想法不是以尽可能最简单的方式访问数据.

您建议使用post请求来访问JSON,这是访问/操作数据的完美有效方式.

REST是一种有意义的数据访问方法.当您在REST中看到请求时,它应立即显示数据发生的情况.

例如:

GET: /cars/make/chevrolet
Run Code Online (Sandbox Code Playgroud)

可能会返回一系列雪佛兰汽车. 一个好的REST api甚至可能在查询字符串中包含一些输出选项,?output=json或者?output=html允许访问者决定应该编码信息的格式.

有点思考如何合理地整合数据类型为REST API后,我已经得出结论,最好的办法明确指定的数据类型是通过已存在的文件扩展名,例如.js,.json,.html,或.xml.丢失的文件扩展名默认为默认格式(例如JSON); 不受支持的文件扩展名可能会返回501 Not Implemented状态代码.

另一个例子:

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }
Run Code Online (Sandbox Code Playgroud)

可能会在数据库中创建一个新的雪佛兰malibu与相关的颜色.我说可能因为REST api不需要与数据库结构直接相关.它只是一个屏蔽接口,以便保护真正的数据(将其视为数据库结构的访问器和更改器).

现在我们需要讨论幂等性问题.通常,REST 通过HTTP 实现CRUD.HTTP使用GET,PUT,POSTDELETE为请求.

一个非常简单的REST实现可以使用以下CRUD映射:

Create -> Post
Read   -> Get
Update -> Put
Delete -> Delete
Run Code Online (Sandbox Code Playgroud)

此实现存在问题:Post被定义为非幂等方法.这意味着后续调用相同的Post方法将导致不同的服务器状态.获取,放置和删除是幂等的; 这意味着多次调用它们会导致相同的服务器状态.

这意味着请求如下:

Delete: /cars/oldest
Run Code Online (Sandbox Code Playgroud)

实际上可以实现为:

Post: /cars/oldest?action=delete
Run Code Online (Sandbox Code Playgroud)

Delete: /cars/id/123456
Run Code Online (Sandbox Code Playgroud)

如果你调用一次,或者你调用它1000次,将导致相同的服务器状态.

处理oldest物品移除的更好方法是请求:

Get: /cars/oldest
Run Code Online (Sandbox Code Playgroud)

并使用ID结果数据发出delete请求:

Delete: /cars/id/[oldest id]
Run Code Online (Sandbox Code Playgroud)

此方法的一个问题是,如果/cars/oldest请求的时间和delete发布时间之间添加了另一个项目.

  • 而不是DELETE:/ cars/oldest,GET如何:/ cars/oldest跟随DELETE?这样,您有两个单独的幂等命令. (10认同)
  • 所以这个答案的问题(这是一个不错的答案,但不完整)是它没有解决他提出的主要问题:为什么你使用HTTP动词和URI而不是自定义JSON数据(可能是某种基于JSON的API调用语法).您可以制作自定义JSON语法,使其"立即...显示数据发生的情况".您不能做的就是在HTTP之上轻松使用内置工具和网络分层,就像遵循所有REST约定的API一样.当然,并不是说我的答案是完美的;) (4认同)
  • @Andre:wiki条目使用的示例是身份验证,缓存和内容类型协商.现在我正在考虑它,你可以将它们与RPC风格的接口一起使用,但诱惑通常是从头开始实现你自己的系统,或者编译到现有系统的集成.使用REST,您可以使用内置集成,并在Web服务器上管理它.这意味着更松散的耦合,这意味着您必须实现更少,并且意味着您的应用程序可以更灵活地在将来更改选项,同时减少代码和测试影响. (4认同)
  • @Andre它是由多种原因组合而来的:遵循HTTP准则意味着当事情发生变化时,您(可能)会有更少的向后兼容性问题; 通过POST使用html表单将警告用户多次提交相同的数据(这是为了防止非幂等事务); 遵循明确的最佳实践是,最好的做法.Rest没有定义特定的实现,允许您根据需要使用它.我建议利用所有HTTP的错误代码和请求方法,但是你可以随意使用它 (3认同)
  • +1; 我同意这是一个很好的答案(我为了娱乐和利润再次重复它).`POST:/ cars/oldest`替换DELETE并没有多大意义.像"POST:/ cars/oldest/delete"这样的东西可能,我认为我更喜欢Neil的解决方案.直接删除对他的get-id-delete-id解决方案的唯一优势是原子性.在我实施这样的事情之前,我想要一个明确的商业理由和一个非人为的场景.您不需要支持所有对象/ URL上的所有动词. (3认同)
  • @MerlynMorgan-Graham,你抓住了我!我完全忘记将删除命令添加回“POST:/cars/oldest”,这只是重复调用服务器会导致不同服务器状态的一个示例,尽管事后看来我从未打开API相反,在相对地址(例如“./oldest”)上执行 POST、PUT 或 DELETE 命令时,它将带有“302 Found”状态代码和“Location:/cars/123”标头。 (2认同)

mar*_*kus 38

这是一个安全性和可维护性问题.

安全的方法

只要有可能,您应该使用"安全"(单向)方法,如GET和HEAD,以限制潜在的漏洞.

幂等方法

只要有可能,您应该使用"幂等"方法,如GET,HEAD,PUT和DELETE,这些方法不会产生副作用,因此不易出错/易于控制.

资源

  • @Computer:执行相同的PUT或相同的DELETE会导致相同的最终状态.*那就是"幂等"的含义. (27认同)
  • 有关更多说明:操作F是幂等的,如果它的单个应用程序及其几个后续应用程序都返回相同的结果.更准确地说,当且仅当F(x)= F(F(x))时,F才是幂等的.例如,Delete是幂等的,因为当您删除一次项目或多次删除它时,结果是相同的:使用删除第一个应用程序只删除一次项目,删除第二个或第三个应用程序中没有任何操作. (4认同)

Nei*_*eil 25

简而言之,REST强调动词的名词.随着API变得越来越复杂,您需要添加更多内容,而不是更多命令.

  • 我有点麻烦让我的头围绕这个.这篇帖子(http://www.lornajane.net/posts/2013/five-clues-that-your-api-isnt-restful#comment-10104)动词应来自HTTP请求,以便URI应该然后只包含名词为我清理了一点 (2认同)

Mer*_*ham 9

你问:

通过普通的$ _POST接受JSON对象,然后以JSON响应也不容易

来自维基百科的REST:

RESTful应用程序可以最大限度地利用所选网络协议提供的预先存在的,定义良好的界面和其他内置功能,并最大限度地减少在其上添加新的特定于应用程序的功能

从我所看到的(很少),我相信这通常是通过最大限度地使用现有的HTTP动词,并为您的服务设计尽可能强大和不言而喻的URL方案来实现的.

不鼓励使用自定义数据协议(即使它们构建在标准数据协议之上,例如SOAP或JSON),并且应该最小化以最好地符合REST意识形态.

另一方面,SOAP RPC over HTTP鼓励每个应用程序设计者定义一个新的和任意的名词和动词词汇表(例如getUsers(),savePurchaseOrder(...)),通常覆盖在HTTP'POST'动词上.这忽略了HTTP的许多现有功能,例如身份验证,缓存和内容类型协商,并且可能使应用程序设计者在新词汇表中重新发明许多这些功能.

您正在使用的实际对象可以是任何格式.我们的想法是尽可能多地重用HTTP来公开用户想要对这些资源执行的操作(查询,状态管理/变异,删除).

你问:

我错过了什么吗?

有关REST和URI语法/ HTTP动词本身的更多信息.例如,一些动词是幂等的,而另一些则不是.我在你的问题中没有看到任何相关内容,所以我没有费心去尝试.其他答案和维基百科都有很多好的信息.

此外,如果您使用的是真正安静的API,那么您可以了解基于HTTP构建的各种网络技术,您可以充分利用这些技术.我从认证开始.


Paw*_*och 8

关于使用扩展来定义数据类型.我注意到MailChimp API正在这样做,但我认为这不是一个好主意.

GET /zzz/cars.json/1

GET /zzz/cars.xml/1
Run Code Online (Sandbox Code Playgroud)

我的声音听起来不错,但我认为"更老"的方法更好 - 使用HTTP标头

GET /xxx/cars/1
Accept: application/json
Run Code Online (Sandbox Code Playgroud)

对于跨数据类型的通信,HTTP标头也更好(如果有人需要它)

POST /zzz/cars
Content-Type: application/xml     <--- indicates we sent XML to server
Accept: application/json          <--- indicates we want get data back in JSON format  
Run Code Online (Sandbox Code Playgroud)


inf*_*rno 5

我错过了什么吗?

是的。;-)

这种现象的存在是由于均匀界面约束。REST 喜欢使用已经存在的标准,而不是重新发明轮子。HTTP 标准已经被证明具有高度可扩展性(Web 已经运行了一段时间)。为什么我们要修复没有损坏的东西?

注意:如果您想将客户端与服务解耦,统一接口约束非常重要。它类似于为类定义接口以将它们彼此解耦。办公室。这里的统一接口由HTTPMIME 类型URIRDF链接数据词汇Hydra 词汇等标准组成。