了解REST:动词,错误代码和认证

我正在寻找一种方法来在我的基于PHP的Web应用程序,数据库和CMS中将API包装在默认函数中。

我环顾四周,发现了几个“骨架”框架。 除了我的问题中的答案外,还有Tonic,我喜欢的REST框架,因为它非常轻便。

我非常喜欢REST,因为它的简单性,并且希望创建一个基于它的API体系结构。 我试图让我的脑袋围绕基本原则,还没有完全理解它。 因此,一些问题。

我的理解是正确的吗?

假设我有一个资源“用户”。 我可以像这样设置一些URI:

/api/users     when called with GET, lists users
/api/users     when called with POST, creates user record
/api/users/1   when called with GET, shows user record
               when called with PUT, updates user record
               when called with DELETE, deletes user record

这是迄今为止RESTful架构的正确表示吗?

我需要更多的动词

在理论上创建,更新和删除可能已经足够,但实际上我会需要更多的动词。 我意识到这些是可以嵌入到更新请求中的东西,但它们是可以具有特定返回码的特定操作,我不想将它们全部置于一个操作中。

在用户示例中想到的一些是:

activate_login
deactivate_login
change_password
add_credit

我将如何表达诸如RESTful URL架构中的操作?

我的直觉是对GET这样的URL进行GET调用

/api/users/1/activate_login 

并期望返回状态码。

这偏离了使用HTTP动词的想法。 你怎么看?

3.如何返回错误消息和代码

REST美丽的一大部分来源于它使用标准的HTTP方法。 发生错误时,我会发送带有3xx,4xx或5xx错误状态码的标题。 有关详细的错误描述,我可以使用正文(对吧?)。 到现在为止还挺好。 但是传输专有错误代码的方式是什么?在描述什么地方出错时(例如“连接数据库失败”或“数据库登录错误”),传输更详细的专有错误代码 ? 如果我把它和信息一起放进身体里,我必须在之后解析它。 这种东西是否有标准头文件?

4.如何进行身份验证

  • 基于REST原则的基于API密钥的认证会是什么样子?
  • 在对REST客户端进行身份验证时,有没有强烈反对使用会话,除了公然违反REST原则? :)(这里只有一半开玩笑,基于会话的身份验证可以与我现有的基础设施配合良好。)

  • 我注意到这个问题晚了几天,但我觉得我可以添加一些见解。 我希望这可以对您的RESTful企业有所帮助。


    要点1:我的理解是正确的吗?

    你理解正确。 这是一个RESTful架构的正确表示。 你可能会发现维基百科的下列矩阵在定义你的名词和动词时非常有用:


    处理Collection URI时: http://example.com/resources/ : http://example.com/resources/

  • GET :列出集合的成员,并附上其成员URI以供进一步导航。 例如,列出所有待售汽车。

  • PUT :含义定义为“用另一个集合替换整个集合”。

  • POST :在由集合自动分配ID的集合中创建一个新条目。 创建的ID通常包含在此操作返回的数据中。

  • DELETE :含义定义为“删除整个集合”。


  • 处理会员 URI时,请执行以下操作: http://example.com/resources/7HOU57Y : http://example.com/resources/7HOU57Y

  • GET :检索以适当的MIME类型表示的收集的寻址成员的表示。

  • PUT :更新集合中已解决的成员或使用指定的ID创建它。

  • POST :将提及的成员视为一个集合,并创建一个新的从属。

  • 删除 :删除收集的编址成员。


  • 第二点:我需要更多的动词

    一般来说,当你认为你需要更多的动词时,它可能实际上意味着你的资源需要被重新识别。 请记住,在REST中,您始终在采用资源或资源集合。 您选择的资源对于您的API定义非常重要。

    激活/取消激活登录 :如果您正在创建新的会话,那么您可能需要将“会话”视为资源。 要创建新会话,请使用POST将http://example.com/sessions/与身份凭证一起使用。 要过期,请使用PUT或DELETE(可能取决于您是否打算保留会话历史记录)到http://example.com/sessions/SESSION_ID

    更改密码:这次资源是“用户”。 您需要在http://example.com/users/USER_ID使用PUT,并在主体中使用旧密码和新密码。 您正在处理“用户”资源,而更改密码只是一个更新请求。 它与关系数据库中的UPDATE语句非常相似。

    我的直觉是对/api/users/1/activate_login这样的URL进行GET调用

    这违背了一个非常核心的REST原则:正确使用HTTP动词。 任何GET请求都不应该有任何副作用。

    例如,GET请求不应在数据库上创建会话,返回带有新会话ID的cookie,或在服务器上留下任何残留。 GET动词就像数据库引擎中的SELECT语句。 请记住,使用GET动词的任何请求的响应应具有缓存功能,请求时使用相同的参数,就像请求静态网页一样。


    第3点:如何返回错误消息和代码

    考虑4xx或5xx HTTP状态码作为错误类别。 您可以详细说明正文中的错误。

    无法连接到数据库: / 不正确的数据库登录 :通常,对于这些类型的错误应该使用500错误。 这是服务器端错误。 客户没有做错什么。 500错误通常被认为是“可重试的”。 即客户端可以重试相同的确切请求,并希望一旦服务器的问题得到解决,它就会成功。 在正文中指定细节,以便客户能够为我们的人类提供一些背景。

    另一类错误是4xx系列,这通常表明客户做错了什么。 特别是,这类错误通常会向客户端指出,不需要重试请求,因为它会继续永久失败。 即在重试此请求之前,客户端需要更改某些内容。 例如,“未找到资源”(HTTP 404)或“格式错误的请求”(HTTP 400)错误将属于此类别。


    第4点:如何进行身份验证

    正如第1点所指出的那样,您可能需要考虑创建会话,而不是对用户进行身份验证。 您将返回一个新的“会话ID”以及相应的HTTP状态代码(200:Access Granted或403:Access Denied)。

    然后你会问你的RESTful服务器:“你能为我获得这个会话ID的资源吗?”。

    没有认证模式 - REST是无状态的:您创建一个会话,您要求服务器使用此会话ID作为参数为您提供资源,并在注销时删除或过期会话。


    简而言之,你是完全落后的。

    你不应该使用你应该使用的URL来解决这个问题。 一旦你确定了你的系统需要哪些资源,以及你将如何表示这些资源以及资源和应用程序状态之间的交互,这些URL将会“免费”。

    引用Roy Fielding的话

    REST API应该花费几乎所有的描述性努力来定义用于表示资源和驱动应用程序状态的媒体类型,或者为现有标准媒体类型定义扩展关系名称和/或启用超文本的标记。 用于描述在感兴趣的URI上使用什么方法的任何努力应该在媒体类型的处理规则的范围内(并且在大多数情况下已经由现有媒体类型定义)完全定义。 [这里的失败意味着带外信息正在推动交互而不是超文本。]

    人们总是从URI开始,认为这是解决方案,然后他们往往会错过REST架构中的一个关键概念,值得注意的是,如上所述,“这里的失败意味着带外信息正在推动交互而不是超文本。 “

    说实话,很多人看到一堆URI和一些GET和PUT和POST,并认为REST很容易。 REST并不容易。 基于HTTP的RPC很容易,通过HTTP有效载荷来回传输数据块很容易。 然而,REST超越了这一点。 REST是协议不可知的。 HTTP对于REST系统来说非常流行。

    REST存在于媒体类型,它们的定义以及应用程序如何通过超文本(有效链接)驱动这些资源可用的操作。

    关于REST系统中的媒体类型有不同的看法。 有些人赞成应用程序特定的有效载荷,而另一些人喜欢将现有媒体类型提升为适合应用程序的角色。 例如,一方面,您可以通过微格式和其他机制,为您的应用程序设计适合您的应用程序的特定XML模式,而不是使用类似XHTML的方式。

    这两种方法都有它们的位置,我认为,XHTML在与人类驱动和机器驱动的网络重叠的场景中工作得非常好,而前者,我觉得更好的更具体的数据类型更容易实现机器到机器的交互。 我发现商品格式的提升可能会使内容谈判变得困难。 “application / xml + yourresource”作为媒体类型比“application / xhtml + xml”更具体,因为后者可以应用于许多有效载荷,这可能是机器客户端实际上感兴趣的,也可能不是没有反省就决定了。

    但是,XHTML在网络浏览器和渲染非常重要的人类网络中工作得非常好(显然)。

    您的应用程序将指导您进行这些决策。

    设计REST系统的一部分工作就是发现系统中的第一类资源以及支持主资源操作所必需的衍生支持资源。 一旦资源被发现,那么这些资源的表示,以及状态图显示资源流通过表示内的超文本,因为下一个挑战。

    回想一下,在超文本系统中,资源的每种表示都将实际的资源表示以及可用于资源的状态转换组合在一起。 考虑每个资源是图中的一个节点,其中链接是将该节点留给其他状态的行。 这些链接不仅告诉客户可以做什么,而且需要做什么(作为一个好的链接结合URI和所需的媒体类型)。

    例如,您可能有:

    <link href="http://example.com/users" rel="users" type="application/xml+usercollection"/>
    <link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
    

    您的文档将讨论名为“users”的rel字段以及“application / xml + youruser”的媒体类型。

    这些链接可能看起来多余,它们都在与相同的URI进行交谈,非常多。 但他们不是。

    这是因为对于“用户”关系,该链接正在讨论用户的集合,并且您可以使用统一接口来处理集合(GET可以检索所有这些集合,也可以使用DELETE删除所有这些集合等)

    如果您发布到此URL,您将需要传递一个“application / xml + usercollection”文档,该文档可能只包含文档中的单个用户实例,因此您可以添加该用户,或者不添加一旦。 也许你的文档会建议你只需传递一个用户类型,而不是集合。

    您可以看到应用程序需要执行搜索的内容,如“搜索”链接所定义的,它是中介类型。 搜索媒体类型的文档将告诉您这是如何运行的,以及期望的结果。

    然而,这里的外观是URI本身基本上不重要。 应用程序控制着URI,而不是客户端。 除了一些“入口点”之外,客户应该依靠应用程序提供的URI来工作。

    客户需要知道如何操作和解释媒体类型,但并不需要太在意它的去向。

    客户眼中这两个链接在语义上是相同的:

    <link href="http://example.com/users?search" rel="search" type="application/xml+usersearchcriteria"/>
    <link href="http://example.com/AW163FH87SGV" rel="search" type="application/xml+usersearchcriteria"/>
    

    所以,关注你的资源。 关注他们在应用程序中的状态转换以及最佳实现方式。


    重新1 :这看起来很好。 请记住在“Location:”标题中返回新创建的用户的URI,作为对POST的响应的一部分,以及“201 Created”状态代码。

    重新2 :通过GET激活是一个坏主意,在URI中包含动词是一种设计气味。 您可能需要考虑在GET上返回表单。 在一个Web应用程序中,这将是一个带有提交按钮的HTML表单; 在API用例中,您可能想要返回一个包含要PUT的URI的表示以激活该帐户。 当然,您也可以在/ POST用户的响应中包含此URI。 使用PUT将确保您的请求具有幂等性,例如,如果客户端不确定成功,它可以安全地再次发送。 一般来说,想想你可以把动词变成什么资源(“动词的名词化”)。 问问自己,你的具体行为最符合什么方法。 例如change_password - > PUT; 停用 - >可能会删除; add_credit - >可能是POST或者PUT。 将客户端指向适当的URI,方法是将它们包含在您的表示中。

    3.不要发明新的状态码,除非你认为它们如此通用,它们值得在全球范围内标准化。 尽量使用最适合的状态码(在RFC 2616中阅读所有这些码)。 在响应主体中包含更多信息。 如果你真的确实想要发明一个新的状态码,那么再想一想; 如果您仍然相信,请确保至少选择正确的类别(1xx - > OK,2xx - >信息,3xx - >重定向; 4xx->客户端错误,5xx - >服务器错误)。 我提到发明新的状态代码是一个坏主意吗?

    4.如果可能,请使用HTTP内置的身份验证框架。 查看Google在GData中进行身份验证的方式。 通常,不要将API密钥放入您的URI中。 尽量避免会话增强可伸缩性并支持缓存 - 如果对请求的响应因以前发生的事情而异,则通常会将自己绑定到特定的服务器流程实例。 将会话状态变为任何一种客户端状态(例如,使其成为后续请求的一部分)或通过将其变为(服务器)资源状态来明确,即给它自己的URI,会更好。

    链接地址: http://www.djcxy.com/p/1221.html

    上一篇: Understanding REST: Verbs, error codes, and authentication

    下一篇: REST API error return good practices