diff --git a/chapters/common-headers.adoc b/chapters/common-headers.adoc index f8f79944a..a6e7178fb 100644 --- a/chapters/common-headers.adoc +++ b/chapters/common-headers.adoc @@ -1,69 +1,60 @@ [[common-headers]] = Common Headers -This section describes a handful of headers, which we found raised the -most questions in our daily usage, or which are useful in particular -circumstances but not widely known. +This section describes a handful of headers, which we found raised the most +questions in our daily usage, or which are useful in particular circumstances +but not widely known. [#178] == {MUST} Use Content Headers Correctly -Content or entity headers are headers with a `Content-` prefix. They -describe the content of the body of the message and they can be used in -both, HTTP requests and responses. Commonly used content headers include -but are not limited to: - -* https://tools.ietf.org/html/rfc6266[`Content-Disposition`] can -indicate that the representation is supposed to be saved as a file, and -the proposed file name. -* https://tools.ietf.org/html/rfc7231#section-3.1.2.2[`Content-Encoding`] -indicates compression or encryption algorithms applied to the content. -* https://tools.ietf.org/html/rfc7230#section-3.3.2[`Content-Length`] -indicates the length of the content (in bytes). -* https://tools.ietf.org/html/rfc7231#section-3.1.3.2[`Content-Language`] -indicates that the body is meant for people literate in some human -language(s). -* https://tools.ietf.org/html/rfc7231#section-3.1.4.2[`Content-Location`] -indicates where the body can be found otherwise -(<<179>> for more details]). -* https://tools.ietf.org/html/rfc7233#section-4.2[`Content-Range`] is -used in responses to range requests to indicate which part of the -requested resource representation is delivered with the body. -* https://tools.ietf.org/html/rfc7231#section-3.1.1.5[`Content-Type`] -indicates the media type of the body content. +Content or entity headers are headers with a `Content-` prefix. They describe +the content of the body of the message and they can be used in both, HTTP +requests and responses. Commonly used content headers include but are not +limited to: + +* {Content-Disposition} can indicate that the representation is supposed to be + saved as a file, and the proposed file name. +* {Content-Encoding} indicates compression or encryption algorithms applied to + the content. +* {Content-Length} indicates the length of the content (in bytes). +* {Content-Language} indicates that the body is meant for people literate in + some human language(s). +* {Content-Location} indicates where the body can be found otherwise (<<179>> + for more details]). +* {Content-Range} is used in responses to range requests to indicate which part + of the requested resource representation is delivered with the body. +* {Content-Type} indicates the media type of the body content. [#133] == {MAY} Use Standardized Headers -Use http://en.wikipedia.org/wiki/List_of_HTTP_header_fields[this list] -and mention its support in your OpenAPI definition. +Use http://en.wikipedia.org/wiki/List_of_HTTP_header_fields[this list] and +mention its support in your OpenAPI definition. [#179] == {MAY} Use Content-Location Header -The Content-Location header is _optional_ and can be used in successful -write operations (PUT, POST or PATCH) or read operations (GET, HEAD) to +The {Content-Location} header is _optional_ and can be used in successful write +operations ({PUT}, {POST}, or {PATCH}) or read operations ({GET}, {HEAD}) to guide caching and signal a receiver the actual location of the resource -transmitted in the response body. This allows clients to identify the -resource and to update their local copy when receiving a response with -this header. - -The Content-Location header can be used to support the following use -cases: - -* For reading operations GET and HEAD, a different location than the -requested URI can be used to indicate that the returned resource is -subject to content negotiations, and that the value provides a more -specific identifier of the resource. -* For writing operations PUT and PATCH, an identical location to the -requested URI can be used to explicitly indicate that the returned -resource is the current representation of the newly created or updated -resource. -* For writing operations POST and DELETE, a content location can be used -to indicate that the body contains a status report resource in response -to the requested action, which is available at provided location. - -*Note*: When using the Content-Location header, the Content-Type header +transmitted in the response body. This allows clients to identify the resource +and to update their local copy when receiving a response with this header. + +The Content-Location header can be used to support the following use cases: + +* For reading operations {GET} and {HEAD}, a different location than the + requested URI can be used to indicate that the returned resource is subject + to content negotiations, and that the value provides a more specific + identifier of the resource. +* For writing operations {PUT} and {PATCH}, an identical location to the + requested URI can be used to explicitly indicate that the returned resource + is the current representation of the newly created or updated resource. +* For writing operations {POST} and {DELETE}, a content location can be used to + indicate that the body contains a status report resource in response to the + requested action, which is available at provided location. + +*Note*: When using the {Content-Location} header, the {Content-Type} header has to be set as well. For example: [source,http] @@ -78,66 +69,73 @@ Content-Location: /products/123/images?format=raw [#180] == {SHOULD} Use Location Header instead of Content-Location Header -As the correct usage of Content-Location with respect to semantics and -caching is difficult, we _discourage_ the use of Content-Location. In -most cases it is sufficient to direct clients to the resource location -by using the Location header instead without hitting the -Content-Location specific ambiguities and complexities. +As the correct usage of {Content-Location} with respect to semantics and +caching is difficult, we _discourage_ the use of {Content-Location}. In most +cases it is sufficient to direct clients to the resource location by using +the {Location} header instead without hitting the {Content-Location} specific +ambiguities and complexities. -More details in RFC 7231 -https://tools.ietf.org/html/rfc7231#section-7.1.2[7.1.2 Location], -https://tools.ietf.org/html/rfc7231#section-3.1.4.2[3.1.4.2 -Content-Location] +More details in RFC 7231 {RFC-7231}#section-7.1.2[7.1.2 Location], +{RFC-7231}#section-3.1.4.2[3.1.4.2 Content-Location] [#181] == {MAY} Use the Prefer header to indicate processing preferences -The `Prefer` header defined in -https://tools.ietf.org/html/rfc7240[RFC7240] allows clients to request -processing behaviors from servers. -https://tools.ietf.org/html/rfc7240[RFC7240] pre-defines a number of -preferences and is extensible, to allow others to be defined. Support -for the Prefer header is entirely optional and at the discretion of API -designers, but as an existing Internet Standard, is recommended over -defining proprietary "X-" headers for processing directives. +The {Prefer} header defined in {RFC-7240}[RFC-7240] allows clients to request +processing behaviors from servers. It pre-defines a number of preferences and +is extensible, to allow others to be defined. Support for the {Prefer} header +is entirely optional and at the discretion of API designers, but as an existing +Internet Standard, is recommended over defining proprietary "X-" headers for +processing directives. -The `Prefer` header can defined like this in an API definition: +The {Prefer} header can defined like this in an API definition: [source,yaml] ---- components: headers: - Prefer: + - Prefer: description: | - The RFC7240 Prefer header indicates that particular server - behaviors are preferred by the client but are not required - for successful completion of the request. - # (indicate the preferences supported by the API) + The RFC7240 Prefer header indicates that a particular server behavior + is preferred by the client but is not required for successful completion + of the request (see [RFC 7240](https://tools.ietf.org/html/rfc7240). + The following behaviors are supported by this API: + + # (indicate the preferences supported by the API or API endpoint) + * **respond-async** used to suggest the server to respond as fast as + possible asynchronously using 202 - accepted - instead of waiting for + the result. + * **return=** used to suggest the server to + return using 204 without resource (minimal) or using 200 or 201 with + resource (representation) in the response body on success. + * **wait=** used to suggest a maximum time the server + has time to process the request. + * **handling=** used to suggest the server be strict + and report error conditions or lenient and try to continue - if + possible. type: string required: false ---- -Supporting APIs may return the `Preference-Applied` header also defined -in https://tools.ietf.org/html/rfc7240[RFC7240] to indicate whether the -preference was applied. +Supporting APIs may return the {Preference-Applied} header also defined in +{RFC7240}[RFC-7240] to indicate whether the preference was applied. [#182] == {MAY} Consider Using `ETag` Together With `If-Match`/`If-None-Match` Header When creating or updating resources it may be necessary to expose conflicts and to prevent the 'lost update' or 'initially created' problem. Following -https://tools.ietf.org/html/rfc7232[RFC 7232 "HTTP: Conditional Requests"] -this can be best accomplished by using the {ETag} header together {If-Match} -or {If-None-Match} conditional header. The contents of an {ETag}`: ` -header is either (a) a hash of the response body, (b) a hash of the last -modified field of the entity, or (c) a version number or identifier of the -entity version. +{RFC-7232}[RFC 7232 "HTTP: Conditional Requests"] this can be best accomplished +by using the {ETag} header together {If-Match} or {If-None-Match} conditional +header. The contents of an `ETag: ` header is either (a) a hash of the +response body, (b) a hash of the last modified field of the entity, or (c) a +version number or identifier of the entity version. To expose conflicts between concurrent update operations via {PUT}, {POST}, or {PATCH}, the `If-Match: ` header can be used to force the server to check whether the version of the updated entity is conforming to the -requested ``. If no matching entity is found, the operation is +requested {entity-tag}. If no matching entity is found, the operation is supposed a to respond with status code {412} - precondition failed. Beside other use cases, `If-None-Match: *` can be used in a similar way to @@ -152,36 +150,39 @@ follows in the API definition: ---- components: headers: - ETag: + - ETag: description: | - The RFC7232 ETag header field in a response provides the current entity- - tag for the selected resource. An entity-tag is an opaque identifier for - different versions of a resource over time, regardless whether multiple - versions are valid at the same time. An entity-tag consists of an opaque - quoted string, possibly prefixed by a weakness indicator. + The RFC 7232 ETag header field in a response provides the entity-tag of + a selected resource. The entity-tag is an opaque identifier for versions + and representations of the same resource over time, regardless whether + multiple versions are valid at the same time. An entity-tag consists of + an opaque quoted string, possibly prefixed by a weakness indicator (see + [RFC 7232 Section 2.3](https://tools.ietf.org/html/rfc7232#section-2.3). type: string required: false - example: W/"xy", "5", "7da7a728-f910-11e6-942a-68f728c1ba70" + example: W/"xy", "5", "5db68c06-1a68-11e9-8341-68f728c1ba70" - If-Match: + - If-Match: description: | The RFC7232 If-Match header field in a request requires the server to only operate on the resource that matches at least one of the provided entity-tags. This allows clients express a precondition that prevent the method from being applied if there have been any changes to the - resource. + resource (see [RFC 7232 Section + 3.1](https://tools.ietf.org/html/rfc7232#section-3.1). type: string required: false example: "5", "7da7a728-f910-11e6-942a-68f728c1ba70" - If-None-Match: + - If-None-Match: description: | The RFC7232 If-None-Match header field in a request requires the server to only operate on the resource if it does not match any of the provided entity-tags. If the provided entity-tag is `*`, it is required that the - resource does not exist at all. + resource does not exist at all (see [RFC 7232 Section + 3.2](https://tools.ietf.org/html/rfc7232#section-3.2). type: string required: false @@ -228,7 +229,7 @@ choose your expiration time: ---- components: headers: - Idempotency-Key: + - Idempotency-Key: description: | The idempotency key is a free identifier created by the client to identify a request. It is used by the service to identify subsequent diff --git a/chapters/http-requests.adoc b/chapters/http-requests.adoc index 0179f7e59..4b61417cd 100644 --- a/chapters/http-requests.adoc +++ b/chapters/http-requests.adoc @@ -226,6 +226,9 @@ An operation can be... * [[safe, safe]]{RFC-safe} - the operation semantic is defined to be read-only, meaning it must not have _intended side effects_, i.e. changes, to the server state. +* [[cacheable, cacheable]]{RFC-cacheable} - to indicate that responses are + allowed to be stored for future reuse. In general, requests to safe methods + that do not depend on a current or authoritative response are cacheable. *Note:* The above definitions, of _intended (side) effect_ allows the server to provide additional state changing behavior as logging, accounting, pre- @@ -234,17 +237,17 @@ intended by the operation so that it can be held accountable. Method implementations must fulfill the following basic properties: -[cols="25%,25%,50%",options="header",] +[cols="15%,15%,35%,35%",options="header",] |==================================================== -| HTTP Method | Safe | Idempotent -| {GET} | {YES} | {YES} -| {HEAD} | {YES} | {YES} -| {POST} | {NO} | {AT} No, however you <<229>>. -| {PUT} | {NO} | {YES} -| {PATCH} | {NO} | {AT} No, however you <<229>>. -| {DELETE} | {NO} | {YES} -| {OPTIONS} | {YES} | {YES} -| {TRACE} | {YES} | {YES} +| Method | Safe | Idempotent | Cacheable +| {GET} | {YES} | {YES} | {YES}, but <<227>> +| {HEAD} | {YES} | {YES} | {YES}, but <<227>> +| {POST} | {NO} | {AT} No, but <<229>> | {AT} May, but <<227>> +| {PUT} | {NO} | {YES} | {NO} +| {PATCH} | {NO} | {AT} No, but <<229>> | {NO} +| {DELETE} | {NO} | {YES} | {NO} +| {OPTIONS} | {YES} | {YES} | {NO} +| {TRACE} | {YES} | {YES} | {NO} |==================================================== [#229] diff --git a/chapters/performance.adoc b/chapters/performance.adoc index b3f221f5b..8edbd0fed 100644 --- a/chapters/performance.adoc +++ b/chapters/performance.adoc @@ -4,48 +4,47 @@ [#155] == {SHOULD} Reduce Bandwidth Needs and Improve Responsiveness -APIs should support techniques for reducing bandwidth based on client -needs. This holds for APIs that (might) have high payloads and/or are -used in high-traffic scenarios like the public Internet and -telecommunication networks. Typical examples are APIs used by mobile web -app clients with (often) less bandwidth connectivity. (Zalando is a -'Mobile First' company, so be mindful of this point.) +APIs should support techniques for reducing bandwidth based on client needs. +This holds for APIs that (might) have high payloads and/or are used in +high-traffic scenarios like the public Internet and telecommunication networks. +Typical examples are APIs used by mobile web app clients with (often) less +bandwidth connectivity. (Zalando is a 'Mobile First' company, so be mindful of +this point.) Common techniques include: -* <<156,gzip compression>> -* querying field filters to retrieve a subset of resource attributes -(see <<157>> below) -* paginate lists of data items (see <> below) -* `ETag` and `If-(None-)Match` headers to avoid re-fetching of unchanged -resources (see <<182>> -* pagination for incremental access of larger (result) lists +* compression of request and response bodies (see <<156>>) +* querying field filters to retrieve a subset of resource attributes (see + <<157>> below) +* {ETag} and {If-Match}/{If-None-Match} headers to avoid re-fetching of + unchanged resources (see <<182>>) +* <> for incremental access of larger collections of data items +* caching of master data items, i.e. resources that change rarely or not + at all after creation (see <<227>>). Each of these items is described in greater detail below. [#156] == {SHOULD} Use gzip Compression -Compress the payload of your API’s responses with gzip, unless there’s a -good reason not to — for example, you are serving so many requests that -the time to compress becomes a bottleneck. This helps to transport data -faster over the network (fewer bytes) and makes frontends respond -faster. +Compress the payload of your API’s responses with gzip, unless there’s a good +reason not to — for example, you are serving so many requests that the time to +compress becomes a bottleneck. This helps to transport data faster over the +network (fewer bytes) and makes frontends respond faster. -Though gzip compression might be the default choice for server payload, -the server should also support payload without compression and its -client control via Accept-Encoding request header -- see also -http://tools.ietf.org/html/rfc7231#section-5.3.4[RFC 7231 Section -5.3.4]. The server should indicate used gzip compression via the -Content-Encoding header. +Though gzip compression might be the default choice for server payload, the +server should also support payload without compression and its client control +via {Accept-Encoding} request header -- see also {RFC-7231}#section-5.3.4[RFC +7231 Section 5.3.4]. The server should indicate used gzip compression via the +{Content-Encoding} header. [#157] == {SHOULD} Support Filtering of Resource Fields -Depending on your use case and payload size, you can significantly -reduce network bandwidth need by supporting filtering of returned entity -fields. Here, the client can determine the subset of fields he wants to -receive via the fields query parameter — example see +Depending on your use case and payload size, you can significantly reduce +network bandwidth need by supporting filtering of returned entity fields. Here, +the client can determine the subset of fields he wants to receive via the +fields query parameter — example see https://cloud.google.com/appengine/docs/python/taskqueue/rest/performance#partial-response[Google AppEngine API's partial response]: @@ -171,22 +170,140 @@ GET /order/123?embed=(items) HTTP/1.1 [#227] == {MUST} Document Caching, if Supported -If an API is intended to support caching, it must take care to specify -this ability by defining the caching boundaries i.e. time-to-live and -cache constraints, by providing the `Cache-Control` and `Vary` headers -(Please read https://tools.ietf.org/html/rfc7234[RFC-7234] carefully). +Caching has to take many aspects into account, e.g. general <> of response information, our guideline to protect endpoints +using SSL and <<104, OAuth authorization>>, resource update and invalidation +rules, existence of multiple consumer instances. As a consequence, caching is +in best case complex, in worst case inefficient. -Caching has to take many aspects into account, e.g. general cacheability -of response information, our guideline to protect endpoints using SSL -and <<104,OAuth authorization>>, resource update and invalidation rules, -existence of multiple consumer instances. As a consequence, caching is -in best case complex, in worst case inefficient. Thus, client side and -transparent HTTP caching should be avoided for RESTful APIs unless the -API designer has proven to know better. +As a consequence, client side as well as transparent web caching should be +avoided, unless the service supports and requires it to protect itself, e.g. +in case of a heavily used and therefore rate limited master data service, i.e. +data items that rarely or not at all change after creation. -As default, API providers should set the `Cache-Control: no-cache` header. +As default, API providers and consumers should always set the {Cache-Control} +header set to {Cache-Control-no-store} and assume the same setting, if no +{Cache-Control} header is provided. -**Note:** There is no need to document this default setting, that is -attached to each response automatically by most frameworks. However, any -use deviating from this default must be sufficiently documented. +**Note:** There is no need to document this default setting. However, please +make sure that your framework is attaching this header value by default, or +ensure this manually, e.g. using the best practice of Spring Security as shown +below. Any setup deviating from this default must be sufficiently documented. +[source,http] +---- +Cache-Control: no-cache, no-store, must-revalidate, max-age=0 +---- + +If your service really requires to support caching, please observe the +following rules: + +* Document all <> {GET}, {HEAD}, and {POST} endpoints by declaring + the support of {Cache-Control}, {Vary}, and {ETag} headers in response. + *Note:* you must not define the {Expires} header to prevent redundant and + ambiguous definition of cache lifetime. A sensible default documentation of + these headers is given below. +* Take care to specify the ability to support caching by defining the right + caching boundaries, i.e. time-to-live and cache constraints, by providing + sensible values for {Cache-Control} and {Vary} in your service. We will + explain best practices below. +* Provide efficient methods to warm up and update caches, e.g. as follows: +** In general, you should support <<182, `ETag` Together With `If-Match`/ + `If-None-Match` Header>> on all <> endpoints. +** For larger data items support {HEAD} requests or more efficient {GET} + requests with {If-None-Match} header to check for updates. +** For small data sets provide full collection {GET} requests supporting + {ETag}, as well as {HEAD} requests or {GET} requests with {If-None-Match} + to check for updates. +** For medium sized data sets provide full collection {GET} requests supporting + {ETag} together with <> and {entity-tag} filtering {GET} requests + for limiting the response to changes since the provided {entity-tag}. *Note:* + this is not supported by generic client and proxy caches on HTTP layer. + +*Hint:* For proper cache support you must return {304} without content on a +failed {HEAD} or {GET} request with `If-None-Match: ` instead of {412}. + +[source,yaml] +---- +components: + headers: + - Cache-Control: + description: | + The RFC 7234 Cache-Control header field is providing directives to + control how proxies and clients are allowed to cache responses results + for performance. Clients and proxies are free to not support caching of + results, however if they do, they must obey all directives mentioned in + [RFC-7234 Section 5.2.2](https://tools.ietf.org/html/rfc7234) to the + word. + + In case of caching, the directive provides the scope of the cache + entry, i.e. only for the original user (private) or shared between all + users (public), the lifetime of the cache entry in seconds (max-age), + and the strategy how to handle a stale cache entry (must-revalidate). + Please note, that the lifetime and validation directives for shared + caches are different (s-maxage, proxy-revalidate). + + type: string + required: false + example: "private, must-revalidate, max-age=300" + - Vary: + description: | + The RFC 7231 Vary header field in a response defines which parts of + a request message, aside the target URL and HTTP method, might have + influenced the response. A client or proxy cache must respect this + information, to ensure that it delivers the correct cache entry (see + [RFC-7231 Section + 7.1.4](https://tools.ietf.org/html/rfc7231#section-7.1.4)). + + type: string + required: false + example: "accept-encoding, accept-language" + - ETag: + description: | + The RFC 7232 ETag header field in a response provides the entity-tag of + a selected resource. The entity-tag is an opaque identifier for versions + and representations of the same resource over time, regardless whether + multiple versions are valid at the same time. An entity-tag consists of + an opaque quoted string, possibly prefixed by a weakness indicator (see + [RFC 7232 Section 2.3](https://tools.ietf.org/html/rfc7232#section-2.3). + + type: string + required: false + example: W/"xy", "5", "5db68c06-1a68-11e9-8341-68f728c1ba70" +---- + +The default setting for {Cache-Control} should contain the `private` directive +for endpoints with standard <<104, OAuth authorization>>, as well as the +`must-revalidate` directive to ensure, that the client does not use stale cache +entries. Last, the `max-age` directive should be set to a value between a few +seconds (`max-age=60`) and a few hours (`max-age=86400`) depending on the change +rate of your master data and your requirements to keep clients consistent. + +[source,http] +---- +Cache-Control: private, must-revalidate, max-age=300 +---- + +The default setting for {Vary} is harder to determine correctly. It highly +depends on the API endpoint, e.g. whether it supports compression, accepts +different media types, or requires other request specific headers. To support +correct caching you have to carefully choose the value. However, a good first +default may be: + +[source,http] +---- +Vary: accept, accept-encoding +---- + +Anyhow, this is only relevant, if you encourage clients to install generic +HTTP layer client and proxy caches. + +*Note:* generic client and proxy caching on HTTP level is hard to configure. +Therefore, we strongly recommend to attach the (possibly distributed) cache +directly to the service (or gateway) layer of your application. This relieves +from interpreting the {vary} header and greatly simplifies interpreting the +{Cache-Control} and {ETag} headers. Moreover, is highly efficient with respect +to caching performance and overhead, and allows more advanced. + +Anyhow, please carefully read {RFC-7234}[RFC 7234] before adding any client or +proxy cache. diff --git a/index.adoc b/index.adoc index 42d062e58..9e087f967 100644 --- a/index.adoc +++ b/index.adoc @@ -11,6 +11,16 @@ :keywords: Zalando, Guidelines, RESTful, API, Events, Schema :copyright: CC-BY-SA 3.0 + +// Some link short cuts. +:RFC-7230: https://tools.ietf.org/html/rfc7230 +:RFC-7231: https://tools.ietf.org/html/rfc7231 +:RFC-7232: https://tools.ietf.org/html/rfc7232 +:RFC-7233: https://tools.ietf.org/html/rfc7233 +:RFC-7234: https://tools.ietf.org/html/rfc7234 +:RFC-7240: https://tools.ietf.org/html/rfc7240 + + // Attribute to improve design of key words in titles. :MUST: pass:[Must:] :SHOULD: pass:[Should:] @@ -34,6 +44,7 @@ :OPTIONS: pass:[OPTIONS] :TRACE: pass:[TRACE] + // Attributes to improve design and linking of HTTP status codes :200: pass:[200] :201: pass:[201] @@ -61,6 +72,7 @@ :501: pass:[501] :503: pass:[503] + // Attributes to improve design and anchoring of HTTP status codes :CODE-200: pass:[200] :CODE-201: pass:[201] @@ -94,10 +106,32 @@ // Attributes to improve design and linking of common headers. :ETag: pass:[ETag] +:entity-tag: pass:[<entity-tag>] :If-Match: pass:[If-Match] :If-None-Match: pass:[If-None-Match] + +:Accept: pass:[Accept] +:Accept-Charset: pass:[Accept-Charset] +:Accept-Encoding: pass:[Accept-Encoding] +:Accept-Language: pass:[Accept-Language] + +:Content-Type: pass:[Content-Type] +:Content-Range: pass:[Content-Range] +:Content-Encoding: pass:[Content-Encoding] +:Content-Language: pass:[Content-Language] +:Content-Length: pass:[Content-Length] +:Content-Disposition: pass:[Content-Disposition] +:Content-Location: pass:[Content-Location] :Location: pass:[Location] +:Prefer: pass:[Prefer] +:Preference-Applied: pass:[Preference-Applied] + +:Vary: pass:[Vary] +:Cache-Control: pass:[Cache-Control] +:Cache-Control#no-store: pass:[Cache-Control: no-store] + + // Attributes to improve design and linking of RFC key words. :RFC-safe: pass:[safe] :RFC-idempotent: pass:[idempotent] @@ -105,6 +139,7 @@ + = Zalando RESTful API and Event Scheme Guidelines Zalando SE