我正在寻找一种方法来包装api的默认功能在我的基于php的web应用程序,数据库和cms。

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

我最喜欢REST,因为它简单,并希望基于它创建一个API体系结构。我正在努力理解基本原理,但还没有完全理解。因此,有一些问题。

1. 我理解得对吗?

假设我有一个资源“用户”。我可以像这样设置一些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体系结构的正确表示吗?

2. 我需要更多的动词

创建、更新和删除在理论上可能已经足够了,但实际上我需要更多的动词。我知道这些东西可以嵌入到更新请求中,但它们是特定的操作,可以有特定的返回代码,我不想把它们都扔到一个操作中。

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

activate_login
deactivate_login
change_password
add_credit

我该如何表达像RESTful URL体系结构那样的动作呢?

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

/api/users/1/activate_login 

并等待状态码返回。

但是,这偏离了使用HTTP谓词的想法。你怎么看?

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

A great part of REST's beauty stems from its use of standard HTTP methods. On an error, I emit a header with a 3xx,4xx or 5xx error status code. For a detailed error description, I can use the body (right?). So far so good. But what would be the way to transmit a proprietary error code that is more detailed in describing what went wrong (e.g. "failed to connect to database", or "database login wrong")? If I put it into the body along with the message, I have to parse it out afterwards. Is there a standard header for this kind of thing?

4. 如何进行身份验证

遵循REST原则的基于API密钥的身份验证是什么样子的? 除了公然违反REST原则之外,在验证REST客户机时使用会话是否有强烈的反对之处?:)(这里只是半开玩笑,基于会话的身份验证在我现有的基础设施中可以很好地发挥作用。)


当前回答

其他基本知识

REST有一个统一的接口约束,它规定REST客户端必须依赖于标准,而不是实际REST服务的特定于应用程序的细节,因此REST客户端不会因微小的更改而中断,而且可能是可重用的。

因此,REST客户机和REST服务之间存在一个契约。如果您使用HTTP作为底层协议,那么以下标准是合同的一部分:

HTTP 1.1 method definitions status code definitions cache control headers accept and content-type headers auth headers IRI (utf8 URI) body (pick one) registered application specific MIME type, e.g. maze+xml vendor specific MIME type, e.g. vnd.github+json generic MIME type with application specific RDF vocab, e.g. ld+json & hydra, schema.org application specific profile, e.g. hal+json & profile link param (I guess) hyperlinks what should contain them (pick one) sending in link headers sending in a hypermedia response, e.g. html, atom+xml, hal+json, ld+json&hydra, etc... semantics use IANA link relations and probably custom link relations use an application specific RDF vocab

REST有一个无状态约束,它声明REST服务和客户机之间的通信必须是无状态的。这意味着REST服务不能维护客户端状态,因此您不能拥有服务器端会话存储。你必须验证每一个请求。例如,HTTP基本认证(HTTP标准的一部分)是可以的,因为它会在每个请求中发送用户名和密码。

来回答你的问题

是的,它可以是。

值得一提的是,客户端并不关心IRI结构,他们关心的是语义,因为他们遵循具有链接关系或链接数据(RDF)属性的链接。

关于IRI唯一重要的一点是,单个IRI必须只能标识单个资源。允许单个资源(如用户)拥有许多不同的IRIs。

我们使用/users/123/password这样漂亮的IRIs的原因很简单;当你通过阅读IRI来理解它时,在服务器上编写路由逻辑就容易得多了。

你有更多的动词,如PUT, PATCH, OPTIONS,甚至更多,但你不需要更多…而不是添加新的动词,你必须学习如何添加新的资源。

   deactivate_login -> PUT /login/active false
   change_password -> PUT /user/xy/password "newpass"
   add_credit -> POST /credit/raise {details: {}}

(由于无状态约束,从REST的角度来看,登录没有意义。)

您的用户并不关心问题存在的原因。他们只想知道是否有成功或错误,可能是他们能理解的错误消息,例如:“对不起,但我们不能保存您的帖子。”等等……

HTTP状态标头是标准标头。其他的都应该在身体里。例如,单个报头不足以描述详细的多语言错误消息。

The stateless constraint (along with the cache and layered system constraints) ensures that the service scales well. You surely don't wan't to maintain millions of sessions on the server, when you can do the same on the clients... The 3rd party client gets an access token if the user grants access to it using the main client. After that the 3rd party client sends the access token with every request. There are more complicated solutions, for example you can sign every single request, etc. For further details check the OAuth manual.

相关文献

架构风格与基于网络的软件架构设计 Roy Thomas Fielding博士论文(REST作者) 2000年,加州大学欧文分校 第三代Web api——弥合REST和关联数据之间的差距 Markus Lanthaler博士论文(JSON-LD合著者,Hydra作者) 2014年,奥地利格拉茨理工大学

其他回答

关于REST返回码:将HTTP协议代码和REST结果混淆是错误的。

然而,我看到许多实现混合了它们,许多开发人员可能不同意我的观点。

HTTP返回码与HTTP请求本身相关。REST调用是使用超文本传输协议(Hypertext Transfer Protocol)请求完成的,它的工作级别比调用的REST方法本身要低。REST是一种概念/方法,其输出是业务/逻辑结果,而HTTP结果代码是传输结果。

例如,当你调用/users/时返回“404 Not found”是令人困惑的,因为它可能意味着:

URI错误(HTTP) 没有找到用户(REST)

“403禁止/拒绝访问”可能是指:

需要特别许可。浏览器可以通过询问用户/密码来处理它。(HTTP) 服务器上配置的访问权限错误。(HTTP) 您需要进行身份验证(REST)

这个列表可能会继续出现“500服务器错误”(Apache/Nginx HTTP抛出错误或REST中的业务约束错误)或其他HTTP错误等……

从代码中,很难理解失败的原因是什么,HTTP(传输)失败还是REST(逻辑)失败。

如果HTTP请求物理上被成功执行,它应该总是返回200个代码,不管是否找到记录。因为URI资源是被http服务器找到并处理的。是的,它可能返回一个空集。是否有可能收到一个空网页200作为http结果,对吗?

相反,你可以返回200个HTTP代码和一个带有空数组/对象的JSON,或者使用bool result/success标志来通知所执行的操作状态。

此外,一些互联网提供商可能会拦截您的请求并返回404 http代码。这并不意味着您的数据找不到,而是在传输级别上出了问题。

从维基:

In July 2004, the UK telecom provider BT Group deployed the Cleanfeed content blocking system, which returns a 404 error to any request for content identified as potentially illegal by the Internet Watch Foundation. Other ISPs return a HTTP 403 "forbidden" error in the same circumstances. The practice of employing fake 404 errors as a means to conceal censorship has also been reported in Thailand and Tunisia. In Tunisia, where censorship was severe before the 2011 revolution, people became aware of the nature of the fake 404 errors and created an imaginary character named "Ammar 404" who represents "the invisible censor".

1. 恕我直言,你对如何设计你的资源有正确的想法。我什么都不会改变。

2. 不要试图用更多的动词来扩展HTTP,而是考虑您所提议的动词可以根据基本的HTTP方法和资源减少到什么程度。例如,不使用activate_login谓词,可以设置如下资源:/api/users/1/login/active,这是一个简单的布尔值。要激活登录,只需在那里放一个文档,说'true'或1或其他什么。要停用,请在那里放置一个为空或显示为0或false的文档。

类似地,要更改或设置密码,只需对/api/users/1/password执行put。

无论何时你需要添加一些东西(比如信用),都要考虑post。例如,你可以对类似/api/users/1/credits这样的资源执行POST操作,其主体包含要添加的积分数。同一资源上的PUT操作可以用于覆盖该值而不是添加。主体中带有负数的POST操作将进行减法,以此类推。

3. I'd strongly advise against extending the basic HTTP status codes. If you can't find one that matches your situation exactly, pick the closest one and put the error details in the response body. Also, remember that HTTP headers are extensible; your application can define all the custom headers that you like. One application that I worked on, for example, could return a 404 Not Found under multiple circumstances. Rather than making the client parse the response body for the reason, we just added a new header, X-Status-Extended, which contained our proprietary status code extensions. So you might see a response like:

HTTP/1.1 404 Not Found    
X-Status-Extended: 404.3 More Specific Error Here

这样,像web浏览器这样的HTTP客户端仍然知道如何处理常规的404代码,而更复杂的HTTP客户端可以选择查看X-Status-Extended报头以获得更具体的信息。

4. 对于身份验证,如果可以的话,我建议使用HTTP身份验证。但恕我直言,如果对你来说更容易的话,使用基于cookie的身份验证并没有什么错。

其他基本知识

REST有一个统一的接口约束,它规定REST客户端必须依赖于标准,而不是实际REST服务的特定于应用程序的细节,因此REST客户端不会因微小的更改而中断,而且可能是可重用的。

因此,REST客户机和REST服务之间存在一个契约。如果您使用HTTP作为底层协议,那么以下标准是合同的一部分:

HTTP 1.1 method definitions status code definitions cache control headers accept and content-type headers auth headers IRI (utf8 URI) body (pick one) registered application specific MIME type, e.g. maze+xml vendor specific MIME type, e.g. vnd.github+json generic MIME type with application specific RDF vocab, e.g. ld+json & hydra, schema.org application specific profile, e.g. hal+json & profile link param (I guess) hyperlinks what should contain them (pick one) sending in link headers sending in a hypermedia response, e.g. html, atom+xml, hal+json, ld+json&hydra, etc... semantics use IANA link relations and probably custom link relations use an application specific RDF vocab

REST有一个无状态约束,它声明REST服务和客户机之间的通信必须是无状态的。这意味着REST服务不能维护客户端状态,因此您不能拥有服务器端会话存储。你必须验证每一个请求。例如,HTTP基本认证(HTTP标准的一部分)是可以的,因为它会在每个请求中发送用户名和密码。

来回答你的问题

是的,它可以是。

值得一提的是,客户端并不关心IRI结构,他们关心的是语义,因为他们遵循具有链接关系或链接数据(RDF)属性的链接。

关于IRI唯一重要的一点是,单个IRI必须只能标识单个资源。允许单个资源(如用户)拥有许多不同的IRIs。

我们使用/users/123/password这样漂亮的IRIs的原因很简单;当你通过阅读IRI来理解它时,在服务器上编写路由逻辑就容易得多了。

你有更多的动词,如PUT, PATCH, OPTIONS,甚至更多,但你不需要更多…而不是添加新的动词,你必须学习如何添加新的资源。

   deactivate_login -> PUT /login/active false
   change_password -> PUT /user/xy/password "newpass"
   add_credit -> POST /credit/raise {details: {}}

(由于无状态约束,从REST的角度来看,登录没有意义。)

您的用户并不关心问题存在的原因。他们只想知道是否有成功或错误,可能是他们能理解的错误消息,例如:“对不起,但我们不能保存您的帖子。”等等……

HTTP状态标头是标准标头。其他的都应该在身体里。例如,单个报头不足以描述详细的多语言错误消息。

The stateless constraint (along with the cache and layered system constraints) ensures that the service scales well. You surely don't wan't to maintain millions of sessions on the server, when you can do the same on the clients... The 3rd party client gets an access token if the user grants access to it using the main client. After that the 3rd party client sends the access token with every request. There are more complicated solutions, for example you can sign every single request, etc. For further details check the OAuth manual.

相关文献

架构风格与基于网络的软件架构设计 Roy Thomas Fielding博士论文(REST作者) 2000年,加州大学欧文分校 第三代Web api——弥合REST和关联数据之间的差距 Markus Lanthaler博士论文(JSON-LD合著者,Hydra作者) 2014年,奥地利格拉茨理工大学

使用post当你不知道如何新的资源URI看起来像(你创建新用户,应用程序将分配新用户它的id), PUT更新或创建资源,你知道他们将如何表示(示例:PUT /myfiles/thisismynewfile.txt) 在消息正文中返回错误描述 您可以使用HTTP身份验证(如果足够的话) Web服务应该是状态

详细,但复制自http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html上的HTTP 1.1方法规范

9.3获得

GET方法意味着检索由Request-URI标识的任何信息(以实体的形式)。如果Request-URI指的是一个产生数据的流程,则应将产生的数据作为响应中的实体返回,而不是流程的源文本,除非该文本恰好是流程的输出。

The semantics of the GET method change to a "conditional GET" if the request message includes an If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range header field. A conditional GET method requests that the entity be transferred only under the circumstances described by the conditional header field(s). The conditional GET method is intended to reduce unnecessary network usage by allowing cached entities to be refreshed without requiring multiple requests or transferring data already held by the client.

如果请求消息包含一个Range报头字段,GET方法的语义将更改为“部分GET”。部分GET请求只传输实体的一部分,如第14.35节所述。partial GET方法旨在通过允许完成部分检索的实体而不传输已经由客户端持有的数据来减少不必要的网络使用。

当且仅当GET请求的响应满足第13节中描述的HTTP缓存要求时,该响应是可缓存的。

关于表单使用时的安全注意事项,请参见15.1.3节。

9.5发布

POST方法用于请求源服务器接受请求中包含的实体,作为request - line中由request - uri标识的资源的新附属。POST被设计为允许一个统一的方法覆盖以下函数:

  - Annotation of existing resources;
  - Posting a message to a bulletin board, newsgroup, mailing list,
    or similar group of articles;
  - Providing a block of data, such as the result of submitting a
    form, to a data-handling process;
  - Extending a database through an append operation.

POST方法执行的实际功能由服务器决定,通常依赖于Request-URI。发布的实体隶属于该URI,就像文件隶属于包含它的目录,新闻文章隶属于发布它的新闻组,或者记录隶属于数据库一样。

POST方法执行的操作可能不会产生可以由URI标识的资源。在本例中,200 (OK)或204 (No Content)是适当的响应状态,这取决于响应是否包含描述结果的实体。

如果源服务器上已经创建了资源,响应应该是201(已创建),并包含一个描述请求状态的实体和指向新资源的实体,以及一个Location头(参见14.30节)。

此方法的响应是不可缓存的,除非响应包含适当的Cache-Control或Expires报头字段。然而,303 (See Other)响应可用于指示用户代理检索可缓存资源。

POST请求必须遵守8.2节中规定的消息传输要求。

安全注意事项请参见15.1.3节。

9.6把

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI. If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request. If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be given that reflects the nature of the problem. The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) headers that it does not understand or implement and MUST return a 501 (Not Implemented) response in such cases.

如果请求经过缓存,而request - uri标识了一个或多个当前缓存的实体,那么这些条目应该被视为过期的。此方法的响应不可缓存。

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,

它必须发送一个301(永久移动)响应;用户代理可以自行决定是否重定向请求。

单个资源可以由许多不同的uri标识。例如,一篇文章可能有一个用于标识“当前版本”的URI,它与标识每个特定版本的URI是分开的。在这种情况下,一个通用URI上的PUT请求可能会导致原始服务器定义多个其他URI。

HTTP/1.1没有定义PUT方法如何影响源服务器的状态。

PUT请求必须遵守8.2节中规定的消息传输要求。

除非对特定的实体-头另有指定,否则PUT请求中的实体-头应该应用于PUT创建或修改的资源。

9.7删除

The DELETE method requests that the origin server delete the resource identified by the Request-URI. This method MAY be overridden by human intervention (or other means) on the origin server. The client cannot be guaranteed that the operation has been carried out, even if the status code returned from the origin server indicates that the action has been completed successfully. However, the server SHOULD NOT indicate success unless, at the time the response is given, it intends to delete the resource or move it to an inaccessible location.

如果响应包含描述状态的实体,那么成功的响应应该是200 (OK),如果操作尚未实施,则应该是202(已接受),如果操作已经实施,但响应不包括实体,则应该是204 (No Content)。

如果请求经过缓存,而request - uri标识了一个或多个当前缓存的实体,那么这些条目应该被视为过期的。此方法的响应不可缓存。