From 26b4513995a1079902894dd72f62361f6846190c Mon Sep 17 00:00:00 2001 From: tkrop Date: Wed, 22 Nov 2023 14:29:55 +0100 Subject: [PATCH] feat: improve response code guidance (#787, #762, #737) Signed-off-by: tkrop --- chapters/http-requests.adoc | 291 +++++++++++---------- chapters/http-status-codes-and-errors.adoc | 278 +++++++++++--------- index.adoc | 3 + 3 files changed, 310 insertions(+), 262 deletions(-) diff --git a/chapters/http-requests.adoc b/chapters/http-requests.adoc index 132d58d9..5bc53332 100644 --- a/chapters/http-requests.adoc +++ b/chapters/http-requests.adoc @@ -14,11 +14,11 @@ Be compliant with the standardized HTTP semantics (see {RFC-9110}[RFC-9110 {GET} requests are used to *read* either a single or a collection resource. -* {GET} requests for individual resources will usually generate a {404} if the -resource does not exist +* {GET} requests for individual resources will usually generate a {404} (if the + resource does not exist). * {GET} requests for collection resources may return either {200} (if the -collection is empty) or {404} (if the collection is missing) -* {GET} requests must NOT have a request body payload (see {GET-with-Body}) + collection is empty) or {404} (if the collection is missing). +* {GET} requests must NOT have a request body payload (see {GET-with-Body}). *Note:* {GET} requests on collection resources should provide sufficient <<137, filter>> and <> mechanisms. @@ -30,17 +30,17 @@ collection is empty) or {404} (if the collection is missing) APIs sometimes face the problem, that they have to provide extensive structured request information with {GET}, that may conflict with the size limits of clients, load-balancers, and servers. As we require APIs to be standard conform -(request body payload in {GET} must be ignored on server side), API designers have to check the -following two options: +(request body payload in {GET} must be ignored on server side), API designers +have to check the following two options: 1. {GET} with URL encoded query parameters: when it is possible to encode the request information in query parameters, respecting the usual size limits of clients, gateways, and servers, this should be the first choice. The request information can either be provided via multiple query parameters or by a single structured URL encoded string. -2. {POST} with body payload content: when a {GET} with URL encoded query parameters - is not possible, a {POST} request with body payload must be used, and explicitly - documented with a hint like in the following example: +2. {POST} with body payload content: when a {GET} with URL encoded query + parameters is not possible, a {POST} request with body payload must be used, + and explicitly documented with a hint like in the following example: [source,yaml] ---- @@ -48,8 +48,9 @@ paths: /products: post: description: > - [GET with body payload](https://opensource.zalando.com/restful-api-guidelines/#get-with-body) - no resources created: - Returns all products matching the query passed as request input payload. + [GET with body payload](https://opensource.zalando.com/restful-api-guidelines/#get-with-body) + - no resources created: Returns all products matching the query passed + as request input payload. requestBody: required: true content: @@ -68,10 +69,10 @@ switching to headers does not solve the original problem. *Hint:* As {GET-with-Body} is used to transport extensive query parameters, the {cursor} cannot any longer be used to encode the query filters in case of <<160, cursor-based pagination>>. As a consequence, it is best practice to -transport the query filters in the body payload, while using <<161, pagination links>> -containing the {cursor} that is only encoding the page position and direction. -To protect the pagination sequence the {cursor} may contain a hash over all -applied query filters (See also <<161>>). +transport the query filters in the body payload, while using <<161, pagination +links>> containing the {cursor} that is only encoding the page position and +direction. To protect the pagination sequence the {cursor} may contain a hash +over all applied query filters (See also <<161>>). [[put]] @@ -83,28 +84,32 @@ as _"please put the enclosed representation at the resource mentioned by the URL, replacing any existing resource."_. * {PUT} requests are usually applied to single resources, and not to collection -resources, as this would imply replacing the entire collection + resources, as this would imply replacing the entire collection. * {PUT} requests are usually robust against non-existence of resources by -implicitly creating the resource before updating -* on successful {PUT} requests, the server will *replace the entire resource* -addressed by the URL with the representation passed in the payload (subsequent -reads will deliver the same payload, plus possibly server-generated fields like `modified_at`) -* successful {PUT} requests return {200} or {204} (if the resource was updated - -with or without returning the resource), {201} (if the resource was created) -or {202} (if accepted and processed asynchronously). - -The updated/created resource may be returned as response payload. We recommend, -to not use it per default, but if the resource is enriched with server-generated -fields like `version_number`. You may also support client side steering (see <<181>>). - -*Important:* It is good practice to keep the resource identifier management under -control of the service provider and not the client, and, hence, to prefer {POST} for -creation of (at least top-level) resources, and focus {PUT} on its usage for updates. -However, in situations where the identifier and all resource attributes -are under control of the client as input for the resource creation you should use -{PUT} and pass the resource identifier as URL path parameter. + implicitly creating the resource before updating. +* On successful {PUT} requests, the server will *replace the entire resource* + addressed by the URL with the representation passed in the payload. + Subsequent reads will deliver the same payload, plus possibly + server-generated fields like `modified_at`. +* Successful {PUT} requests return {200} or {204} (if the resource was updated + -- with or without returning the resource), {201} (if the resource was newly + created), and {202} (if the request was accepted for asynchronous + processing). + +The updated/created resource may be returned as response payload. We recommend, +to not use it per default, but if the resource is enriched with +server-generated fields like `version_number`. You may also support client side +steering (see <<181>>). + +*Important:* It is good practice to keep the resource identifier management +under control of the service provider and not the client, and, hence, to prefer +{POST} for creation of (at least top-level) resources, and focus {PUT} on its +usage for updates. However, in situations where the identifier and all resource +attributes are under control of the client as input for the resource creation +you should use {PUT} and pass the resource identifier as URL path parameter. Putting the same resource twice is required to be <> and to result -in the same single resource instance (see <<149>>) without data duplication in case of repetition. +in the same single resource instance (see <<149>>) without data duplication in +case of repetition. *Hint:* To prevent unnoticed concurrent updates and duplicate creations when using {PUT}, you <<182>> to allow the server to react on stricter demands that @@ -119,23 +124,31 @@ details and options. collection resource endpoint, but other semantics on single resources endpoint are equally possible. The semantic for collection endpoints is best described as _"please add the enclosed representation to the collection resource -identified by the URL"_. The semantic for single resource endpoints is best described -as _"please execute the given well specified request on the resource identified -by the URL"_. - -* on a successful {POST} request, the server will create one or multiple new -resources and provide their URI/URLs in the response -* successful {POST} requests return {200} or {204} (if the resource was updated - -with or without returning the resource), {201} (if the resource was created) -or {202} (if accepted and processed asynchronously). - -*Note:* By using {POST} to create resources the resource ID must not be passed as -request input date by the client, but created and maintained by the service and -returned with the response payload. - -Apart from resource creation, {POST} should be also used for scenarios that cannot -be covered by the other methods sufficiently. However, in such cases make sure to -document the fact that {POST} is used as a workaround (see e.g. {GET-with-Body}). +identified by the URL"_. The semantic for single resource endpoints is best +described as _"please execute the given well specified request on the resource +identified by the URL"_. + +* On a successful {POST} request, the server will create one or multiple new + resources, usually returning the resources or their URI/URLs in the response. + * For a single resource (tree) {POST} is expected to utilize the {Location} + header pointing to the URL of the newly created resource (tree) -- with or + without returning the resource (tree). + * For multiple resources {POST} may either return a collection of newly + created resources as served by the {GET} collection endpoint, or a bulk + response using the status code {207} (see also <<152>>). +* Successful {POST} requests return {200} or {204} (if the resource was updated + -- with or without returning the resource), {201} (if the resource was newly + created), and {202} (if the request was accepted for asynchronous + processing). + +*Note:* By using {POST} to create resources the resource ID must not be passed +as request input date by the client, but created and maintained by the service +and returned with the response payload. + +Apart from resource creation, {POST} should be also used for scenarios that +cannot be covered by the other methods sufficiently. However, in such cases +make sure to document the fact that {POST} is used as a workaround (see e.g. +{GET-with-Body}). *Hint:* Posting the same resource twice is *not* required to be <> (check <<149>>) and may result in multiple resources. However, you <<229>> to @@ -147,43 +160,43 @@ prevent this. {PATCH} method extends HTTP via {RFC-5789}[RFC-5789] standard to update parts of the resource objects where e.g. in contrast to {PUT} only a specific subset -of resource fields should be changed. The set of changes is represented -in a format called a _patch document_ passed as payload and identified by a -specific media type. The semantic is best -described as _"please change the resource identified by the URL according to my -patch document"_. The syntax and semantics of the patch document is not -defined in {RFC-5789}[RFC-5789] and must be described in the API specification -by using specific media types. +of resource fields should be changed. The set of changes is represented in a +format called a _patch document_ passed as payload and identified by a specific +media type. The semantic is best described as _"please change the resource +identified by the URL according to my patch document"_. The syntax and +semantics of the patch document is not defined in {RFC-5789}[RFC-5789] and must +be described in the API specification by using specific media types. * {PATCH} requests are usually applied to single resources as patching entire -collection is challenging + collection is challenging. * {PATCH} requests are usually not robust against non-existence of resource -instances -* on successful {PATCH} requests, the server will update parts of the resource -addressed by the URL as defined by the change request in the payload -* successful {PATCH} requests return {200} or {204} (if the resource was updated - -with or without returning the resource). - -*Note:* since implementing {PATCH} correctly is a bit tricky, we strongly suggest -to choose one and only one of the following patterns per endpoint (unless -forced by a <<106,backwards compatible change>>). In preference order: - -1. use {PUT} with complete objects to update a resource as long as feasible + instances. +* On successful {PATCH} requests, the server will update parts of the resource + addressed by the URL as defined by the change request in the payload. +* Successful {PATCH} requests return {200} or {204} (if the resource was + updated -- with or without returning the resource), and {202} (if the request + was accepted for asynchronous processing). + +*Note:* since implementing {PATCH} correctly is a bit tricky, we strongly +suggest to choose one and only one of the following patterns per endpoint +(unless forced by a <<106,backwards compatible change>>). In preference order: + +1. Use {PUT} with complete objects to update a resource as long as feasible (i.e. do not use {PATCH} at all). -2. use {PATCH} with {RFC-7396}[JSON Merge Patch] standard, a +2. Use {PATCH} with {RFC-7396}[JSON Merge Patch] standard, a specialized media type `application/merge-patch+json` for partial resource representation to update parts of resource objects. -3. use {PATCH} with {RFC-6902}[JSON Patch] standard, a specialized media type +3. Use {PATCH} with {RFC-6902}[JSON Patch] standard, a specialized media type `application/json-patch+json` that includes instructions on how to change the resource. -4. use {POST} (with a proper description of what is happening) instead of +4. Use {POST} (with a proper description of what is happening) instead of {PATCH}, if the request does not modify the resource in a way defined by the semantics of the standard media types above. In practice {RFC-7396}[JSON Merge Patch] quickly turns out to be too limited, especially when trying to update single objects in large collections (as part -of the resource). In this case {RFC-6902}[JSON Patch] is more powerful -while still showing readable patch requests (see also +of the resource). In this case {RFC-6902}[JSON Patch] is more powerful while +still showing readable patch requests (see also http://erosb.github.io/post/json-patch-vs-merge-patch[JSON patch vs. merge]). JSON Patch supports changing of array elements identified via its index, but not via (key) fields of the elements as typically needed for collections. @@ -208,10 +221,11 @@ described as _"please delete the resource identified by the URL"_. collection resources, as this would imply deleting the entire collection. * {DELETE} request can be applied to multiple resources at once using query parameters on the collection resource (see <>). -* successful {DELETE} requests return {200} or {204} (if the resource was deleted - - with or without returning the resource). -* failed {DELETE} requests will usually generate {404} (if the resource cannot - be found) or {410} (if the resource was already deleted before). +* Successful {DELETE} requests return {200} or {204} (if the resource was + deleted -- with or without returning the resource), or {202} (if the request + was accepted for asynchronous processing). +* Failed {DELETE} requests will usually generate {404} (if the resource cannot + be found) or {410} (if the resource was already traceably deleted before). *Important:* After deleting a resource with {DELETE}, a {GET} request on the resource is expected to either return {404} (not found) or {410} (gone) @@ -262,7 +276,7 @@ be similar to usual {DELETE} requests. resources and resource collections. * {HEAD} has exactly the same semantics as {GET}, but returns headers only, no -body. + body. *Hint:* {HEAD} is particular useful to efficiently lookup whether large resources or collection resources have been updated in conjunction with the @@ -276,7 +290,7 @@ resources or collection resources have been updated in conjunction with the methods) of a given endpoint. * {OPTIONS} responses usually either return a comma separated list of methods -in the `Allow` header or as a structured list of link templates + in the `Allow` header or as a structured list of link templates. *Note:* {OPTIONS} is rarely implemented, though it could be used to self-describe the full functionality of a resource. @@ -287,14 +301,14 @@ self-describe the full functionality of a resource. Request methods in RESTful services can be... -* [[safe, safe]]{RFC-safe} - the operation semantic is defined to be read-only, +* [[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. -* [[idempotent, idempotent]]{RFC-idempotent} - the operation has the same +* [[idempotent, idempotent]]{RFC-idempotent} -- the operation has the same _intended effect_ on the server state, independently whether it is executed once or multiple times. *Note:* this does not require that the operation is returning the same response or status code. -* [[cacheable, cacheable]]{RFC-cacheable} - to indicate that responses are +* [[cacheable, cacheable]]{RFC-cacheable} -- to indicate that responses are allowed to be stored for future reuse. In general, requests to safe methods are cacheable, if it does not require a current or authoritative response from the server. @@ -358,8 +372,8 @@ To decide, which pattern is suitable for your use case, please consult the following table showing the major properties of each pattern: [,cols="46%,18%,18%,18%",options="header",] -|================================================================================== -| | Conditional Key | Secondary Key | Idempotency Key +|============================================================================== +| | Conditional Key | Secondary Key | Idempotency Key | Applicable with | {PATCH} | {POST} | {POST}/{PATCH} | HTTP Standard | {YES} | {NO} | {NO} | Prevents duplicate (zombie) resources | {YES} | {YES} | {NO} @@ -368,19 +382,19 @@ following table showing the major properties of each pattern: | Supports exact same response | {NO} | {NO} | {YES} | Can be inspected (by intermediaries) | {YES} | {NO} | {YES} | Usable without previous {GET} | {NO} | {YES} | {YES} -|================================================================================== +|============================================================================== *Note:* The patterns applicable to {PATCH} can be applied in the same way to {PUT} and {DELETE} providing the same properties. If you mainly aim to support safe retries, we suggest to apply <<182, conditional key>> and <<231,secondary key>> pattern before the <<230, -Idempotency Key>> pattern. +idempotency key>> pattern. -Note, like for {PUT}, successful {POST} or {PATCH} returns {200} or {204} (if the resource -was updated - with or without returning the resource), or {201} (if resource was created). -Hence, clients can differentiate successful robust repetition from resource created -server activity of idempotent {POST}. +*Note:* like for {PUT}, successful {POST} or {PATCH} returns {200} or {204} (if +the resource was updated -- with or without returning the resource), or {201} +(if resource was created). Hence, clients can differentiate successful robust +repetition from resource created server activity of idempotent {POST}. [#231] @@ -410,34 +424,35 @@ would be a similar well defined option. [#253] == {MAY} support asynchronous request processing -Typically REST APIs are designed as synchronous interfaces where all server-side -processing and state changes initiated by the call are finished before delivering -the result as response. However, in long running request processing situations -you may make use of asynchronous interface design with multiple calls: one for -initiating the asynchronous processing and subsequent ones for accessing the -processing status and/or result. - -We recommend an API design that represents the asynchronous request processing -explicitly via a job resource that has a status and is different from the actual -business resource. For instance, `POST /report-jobs` returns HTTP status code {201} to -indicate successful initiation of asynchronous processing together with the job-id -passed in the response payload and/or via the URL of the {Location} header. -The job-id or {Location} URL then can be used to poll the processing status -via `GET /report-jobs/{id}` which returns HTTP status code {200} with job status and -optional report-id as response payload. Once returned with job status `finished`, -the report-id is provided and can be used to fetch the result via `GET /reports/{id}` -which returns {200} and the report object as response payload. +Typically REST APIs are designed as synchronous interfaces where all +server-side processing and state changes initiated by the call are finished +before delivering the result as response. However, in long running request +processing situations you may make use of asynchronous interface design with +multiple calls: one for initiating the asynchronous processing and subsequent +ones for accessing the processing status and/or result. + +We recommend an API design that represents the asynchronous request processing +explicitly via a job resource that has a status and is different from the +actual business resource. For instance, `POST /report-jobs` returns HTTP status +code {201} to indicate successful initiation of asynchronous processing +together with the _job-id_ passed in the response payload and/or via the URL of +the {Location} header. The _job-id_ or {Location} URL then can be used to poll +the processing status via `GET /report-jobs/{id}` which returns HTTP status +code {200} with job status and optional report-id as response payload. Once +returned with job status `finished`, the report-id is provided and can be used +to fetch the result via `GET /reports/{id}` which returns {200} and the report +object as response payload. Alternatively, if you do not to follow the recommended practice of providing a -separate job resource, you may use `POST /reports` returning a status code {202} -together with the {Location} header to indicate successful initiation of the -asynchronous processing. The {Location} URL is used to fetch the report via +separate job resource, you may use `POST /reports` returning a status code +{202} together with the {Location} header to indicate successful initiation of +the asynchronous processing. The {Location} URL is used to fetch the report via `GET /reports/{id}` which returns either {200} and the report resource or {202} without payload, if the asynchronous processing is still ongoing. -*Hint:* Do *not* use response code {204} or {404} instead of {202} here -- it is -misleading since neither is the processing successfully finished, nor do we want to -suggest a client failure. +*Hint:* Do *not* use response code {204} or {404} instead of {202} here -- it +is misleading since neither is the processing successfully finished, nor do we +want to suggest a client failure. [#154] @@ -475,10 +490,9 @@ the escaping of special characters and the maximal URL length. [#236] == {SHOULD} design simple query languages using query parameters -We prefer the use of query parameters to describe resource-specific -query languages for the majority of APIs because it's native to HTTP, -easy to extend and has an excellent implementation support in HTTP clients -and web frameworks. +We prefer the use of query parameters to describe resource-specific query +languages for the majority of APIs because it's native to HTTP, easy to extend +and has an excellent implementation support in HTTP clients and web frameworks. By simple query language we mean one or more name-value pairs that are combined in one way only with `and` semantics. @@ -494,8 +508,8 @@ How query parameters are named and used is up to individual API designers, here are a few tips that could help to decide whether to use simple or more complex query language: -1. Consider using simple query language when API is built to be used - by others (external teams): +1. Consider using simple query language when API is built to be used by others + (external teams): * no additional effort/logic to form the query * no ambiguity in meaning of the query parameters. For example @@ -503,10 +517,10 @@ query language: is `user_id` equal to `gt:100`? * easy to read, no learning curve -2. For internal usage or specific use case a more complex query language - can be used (such as `price gt 10` or `price[gt]=10` or `price>10` etc.). - Also please consider following <<237, our guidance>> for designing complex - query languages with JSON. +2. For internal usage or specific use case a more complex query language can be + used (such as `price gt 10` or `price[gt]=10` or `price>10` etc.). Also + please consider following <<237, our guidance>> for designing complex query + languages with JSON. The following examples should serve as ideas for simple query language: @@ -523,15 +537,15 @@ The following examples should serve as ideas for simple query language: === Less than -* `max_length=5` - query elements based on upper/lower bounds (`min` and `max`) -* `shorter_than=5` - query elements using terminology specific e.g. to _length_ +* `max_length=5` -- query elements based on upper/lower bounds (`min` and `max`) +* `shorter_than=5` -- query elements using terminology specific e.g. to _length_ * `price_lower_than=50` or `price_lower_than_or_equal=50` * `created_before=2019-07-17` or `active_until=2023-09-18T12:12:00.000Z` ** Using terminology specific to time: _before_, _after_, _since_ and _until_ === More than -* `min_length=2` - query elements based on upper/lower bounds (`min` and `max`) +* `min_length=2` -- query elements based on upper/lower bounds (`min` and `max`) * `created_after=2019-07-17` or `modified_since=2019-07-17` ** Using terminology specific to time: _before_, _after_, _since_ and _until_ * `price_higher_than=50` or `price_equal_or_higher_than=50` @@ -548,8 +562,8 @@ The following examples should serve as ideas for simple query language: Please check <<137, conventional query parameters for pagination and sorting>> and you can also find additional info in <> section below. -We don't advocate for or against certain names because in the end -APIs should be free to choose the terminology that fits their domain the best. +We don't advocate for or against certain names because in the end APIs should +be free to choose the terminology that fits their domain the best. [#237] @@ -569,8 +583,8 @@ Aspects that set those APIs apart from the rest include but are not limited to: * Dynamic filters, due to a dynamic and extensible resource model * Free choice of operators, e.g. `and`, `or` and `not` -APIs that qualify for a specific, complex query language are encouraged to -use nested JSON data structures and define them using OpenAPI directly. The +APIs that qualify for a specific, complex query language are encouraged to use +nested JSON data structures and define them using OpenAPI directly. The provides the following benefits: * Data structures are easy to use for clients @@ -615,7 +629,8 @@ might look like. Feel free to also get some inspiration from: -* https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html[Elastic Search: Query DSL] +* https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html[Elastic + Search: Query DSL] * https://graphql.org/learn/queries/[GraphQL: Queries] @@ -623,8 +638,8 @@ Feel free to also get some inspiration from: == {MUST} document implicit response filtering Sometimes certain collection resources or queries will not list all the -possible elements they have, but only those for which the current client -is authorized to access. +possible elements they have, but only those for which the current client is +authorized to access. Implicit filtering could be done on: @@ -632,8 +647,8 @@ Implicit filtering could be done on: * the fields returned for the detail information of the resource In such cases, the fact that implicit filtering is applied must be documented -in the API specification's endpoint description. Consider <<227,caching aspects>> -when implicit filtering is provided. Example: +in the API specification's endpoint description. Consider <<227,caching +aspects>> when implicit filtering is provided. Example: If an employee of the company _Foo_ accesses one of our business-to-business service and performs a `{GET} /business-partners`, it must, for legal reasons, diff --git a/chapters/http-status-codes-and-errors.adoc b/chapters/http-status-codes-and-errors.adoc index 032ab872..dab46967 100644 --- a/chapters/http-status-codes-and-errors.adoc +++ b/chapters/http-status-codes-and-errors.adoc @@ -7,10 +7,12 @@ You must only use official HTTP status codes consistently with their intended semantics. Official HTTP status codes are defined via RFC standards and -registered in the https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml[IANA -Status Code Registry]. Main RFC standards are {RFC-7231}#section-6[RFC7231 - HTTP/1.1: Semantics] -(or {RFC-7235}#page-6[RFC7235 - HTTP/1.1: Authentication]) -and {RFC-6585}[RFC 6585 - HTTP: Additional Status Codes] (and there are upcoming new ones, e.g. +registered in the +https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml[IANA +Status Code Registry]. Main RFC standards are {RFC-7231}#section-6[RFC7231 - +HTTP/1.1: Semantics] (or {RFC-7235}#page-6[RFC7235 - HTTP/1.1: Authentication]) +and {RFC-6585}[RFC 6585 - HTTP: Additional Status Codes] (and there are +upcoming new ones, e.g. https://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-05[draft legally-restricted-status]). An overview on the official error codes provides https://en.wikipedia.org/wiki/List_of_HTTP_status_codes[Wikipedia: HTTP status @@ -25,13 +27,12 @@ APIs should define the functional, business view and abstract from implementation aspects. Success and error responses are a vital part to define how an API is used correctly. -Therefore, you must define **all** success and service specific error -responses in your API specification. Both are part of the interface definition -and provide important information for service clients to handle standard as -well as exceptional situations. -Error code response descriptions should provide information about the specific -conditions that lead to the error, especially if these conditions can be -changed by how the endpoint is used by the clients. +Therefore, you must define **all** success and service specific error responses +in your API specification. Both are part of the interface definition and +provide important information for service clients to handle standard as well as +exceptional situations. Error code response descriptions should provide +information about the specific conditions that lead to the error, especially if +these conditions can be changed by how the endpoint is used by the clients. API designers should also think about a **troubleshooting board** as part of the associated online API documentation. It provides information and handling @@ -39,14 +40,14 @@ guidance on application-specific errors and is referenced via links from the API specification. This can reduce service support tasks and contribute to service client and provider performance. -**Exception:** Standard errors, especially for client side error codes -like 401 (unauthenticated), 403 (unauthorized) or 404 (not found) that can be -inferred straightforwardly from the specific endpoint definition need not to be -individually defined. Instead you can combine multiple error response specifications -with the default pattern below. However, you should not use it and explicitly -define the error code as soon as it provides endpoint specific indications -for clients of how to avoid calling the endpoint in the wrong way, -or be prepared to react on specific error situation. +**Exception:** Standard client and server errors, e.g. {401} (unauthenticated), +{403} (unauthorized), {404} (not found), {500} (internal server error), or +{503} (service unavailable), where the semantic can be easily derived from the +end endpoint specification need no individual definition. Instead these can be +included by applying the `default` shown pattern below. However, error codes +that provide endpoint specific indications for clients on how to avoid calling +the endpoint in the wrong way, or be prepared to react on specific error +situation must be specified explicitly. [source,yaml] ---- @@ -88,10 +89,10 @@ Does NOT mean that every operation must be able to return this code. [[status-code-do-not-use]] ==== {do-not-use} -We do not see a good use-case for returning this status code from a RESTful API. -The status code might be applicable in other contexts, e.g. returned by reverse -proxies, for web pages, etc. Implicitly also means {do-not-document}, as -status codes that are not returned by the API should also not be documented. +We do not see a good use-case for returning this status code from a RESTful +API. The status code might be applicable in other contexts, e.g. returned by +reverse proxies, for web pages, etc. Implicitly also means {do-not-document}, +as status codes that are not returned by the API should also not be documented. [[status-code-document]] ==== {document} @@ -104,16 +105,17 @@ The status code has a well-understood standard meaning to it, so only document it if there are operation specific details you want to add. See exception in <<151, rule 151>>. + [[success-codes]] === Success codes - [[status-code-200]] ==== 200 OK {rfc-status-200} {use} {document} {ALL} [.indent] This is the most general success response. It should be used if the more -specific codes below are not applicable. - +specific codes below are not applicable. In a robust resource creation via +{POST}, {PUT}, and {PATCH} in conjunction with a {201} this indicates that the +returned resource exists before. [[status-code-201]] ==== 201 Created {rfc-status-201} {use} {document} {POST} {PUT} @@ -128,17 +130,15 @@ response header (see <<133>>). ==== 202 Accepted {rfc-status-202} {use} {document} {POST} {PUT} {PATCH} {DELETE} [.indent] The request was successful and will be processed asynchronously. -Only applicable to methods which change something, with the exception of +Only applicable to methods which change something, with the exception of {GET} methods indicating that a resources is still created asynchronously as described in <<253>>. - [[status-code-204]] -==== 204 No content {rfc-status-204} {document} {PUT} {PATCH} {DELETE} +==== 204 No content {rfc-status-204} {use} {document} {PUT} {PATCH} {DELETE} [.indent] -Returned instead of {200}, if no response payload is returned. -Normally only applicable to methods which change something. - +Returned instead of {200}, if no response payload is returned. Normally only +applicable to methods which change something. [.do-not-use] [[status-code-205]] @@ -147,7 +147,6 @@ Normally only applicable to methods which change something. This is meant for interactive use cases, e.g. to clear a form after submitting it. There is no reason to use it in a REST API. - [.do-not-use] [[status-code-206]] ==== 206 Partial Content {rfc-status-206} {do-not-use} {ALL} @@ -157,7 +156,6 @@ the byte range is returned. This is not for pagination, where a normal {200} should be used. This might be useful in rare cases (like media streaming or downloading large files), but most APIs don't need this. - [[status-code-207]] ==== 207 Multi-Status {rfc-status-207} {use} {document} {POST} ({DELETE}) [.indent] @@ -169,16 +167,12 @@ cases also for {DELETE}. [[redirection-codes]] === Redirection codes -See <<250>>. - - [.do-not-use] [[status-code-301]] ==== 301 Moved Permanently {rfc-status-301} {do-not-use} {ALL} [.indent] -This and all future requests should be directed to the -given URI. - +This and all future requests should be directed to the given URI. See also +<<251>>. [.do-not-use] [[status-code-302]] @@ -186,35 +180,32 @@ given URI. [.indent] This is a temporary redirect where some clients {MAY} change the request method from {POST} to {GET}. Mainly used for dismissing and redirecting form -submissions in browsers. - +submissions in browsers. See also <<251>>. [.do-not-use] [[status-code-303]] ==== 303 See Other {rfc-status-303} {do-not-use} {POST} {PUT} {PATCH} {DELETE} [.indent] -The response to the request can be found under another URI using a -{GET} method. A disambiguated version of {302} for the case where the client -{MUST} change the method to {GET}. - +The response to the request can be found under another URI using a {GET} +method. A disambiguated version of {302} for the case where the client {MUST} +change the method to {GET}. See also <<251>>. [[status-code-304]] ==== 304 Not Modified {rfc-status-304} {document} {GET} {HEAD} [.indent] Indicates that a conditional {GET} or {HEAD} request would have resulted in -{200} response if it were not for the fact that the condition evaluated to false -i.e. resource has not been modified since the date or version passed via request -headers {If-Modified-Since} or {If-None-Match}. For {PUT}/{PATCH}/{DELETE} -requests, use {412} instead. +{200} response, if it were not for the fact that the condition evaluated to +false, i.e. resource has not been modified since the date or version passed via +request headers {If-Modified-Since} or {If-None-Match}. For +{PUT}/{PATCH}/{DELETE} requests, use {412} instead. [.do-not-use] [[status-code-307]] ==== 307 Temporary Redirect {rfc-status-307} {do-not-use} {ALL} [.indent] The response to the request can be found under another URI. A disambiguated -version of {302} where the client {MUST} keep the same method as the -original request. - +version of {302} where the client {MUST} keep the same method as the original +request. See also <<251>>. [.do-not-use] [[status-code-308]] @@ -222,7 +213,8 @@ original request. [.indent] Similar to {307}, but the client should persist the new URI. Applicable more to browsers. For APIs, the URI should be explicitly fixed at the source instead of -being implicitly kept in some state based on a previous redirect. +being implicitly kept in some state based on a previous redirect. See also +<<251>>. [[client-side-error-codes]] @@ -236,7 +228,6 @@ due to something that is perceived to be a client error (e.g. malformed request syntax, invalid request). Should also be delivered in case of input payload fails business logic / semantic validation (instead of using {422}). - [[status-code-401]] ==== 401 Unauthorized {rfc-status-401} {use} {do-not-document} {ALL} [.indent] @@ -245,7 +236,6 @@ target resource. For an API, this usually means that the provided token or cookie is not valid. As this can happen for almost every endpoint, APIs should normally not document this. - [[status-code-403]] ==== 403 Forbidden {rfc-status-403} {do-not-document} {ALL} [.indent] @@ -254,36 +244,33 @@ the request's token was valid, but was missing a scope for this endpoint. Or that some object-specific authorization failed. We recommend only documenting the second case. - [[status-code-404]] -==== 404 Not found {rfc-status-404} {do-not-document} {ALL} +==== 404 Not found {rfc-status-404} {use} {do-not-document} {ALL} [.indent] -The target resource was not found. This will be returned by most (not documented) paths on most -APIs, and for endpoints with parameters when those parameters don't map to an -existing entity. For a {PUT} endpoint which only supports updating existing -resources, this might be returned if the resource does not exist. Apart from -these special cases, this does not need to be documented. - +The target resource was not found. This will be returned by most paths on most +APIs (with out being documented), and for endpoints with parameters when those +parameters cannot be map to an existing entity. For a {PUT} endpoint which only +supports updating existing resources, this might be returned if the resource +does not exist. Apart from these special cases, this does not need to be +documented. [[status-code-405]] ==== 405 Method Not Allowed {rfc-status-405} {document} {ALL} [.indent] The request method is not supported for this resource. In theory, this can be -returned for all resources for all the methods except the ones documented. Using -this response code for an existing endpoint (usually with path parameter) only -makes sense if it depends on some internal resource state whether a specific -method is allowed, e.g. an order can only be canceled via {DELETE} until the -shipment leaves the warehouse. *Do not use it unless you have such a special use -case, but then make sure to document it, making it clear why a resource might -not support a method.* - +returned for all resources for all the methods except the ones documented. +Using this response code for an existing endpoint (usually with path +parameters) only makes sense if it depends on some internal resource state +whether a specific method is allowed, e.g. an order can only be canceled via +{DELETE} until the shipment leaves the warehouse. *Do not use it unless you +have such a special use case, but then make sure to document it, making it +clear why a resource might not support a method.* [[status-code-406]] -==== 406 Not Acceptable {rfc-status-406} {do-not-document} {ALL} +==== 406 Not Acceptable {rfc-status-406} {use} {do-not-document} {ALL} [.indent] -Resource only supports generating content with content-types that are not listed -in the {Accept} header sent in the request. - +Resource only supports generating content with content-types that are not +listed in the {Accept} header sent in the request. [.do-not-use] [[status-code-408]] @@ -292,7 +279,6 @@ in the {Accept} header sent in the request. The server times out waiting for the request to arrive. For APIs, this should not be used. - [[status-code-409]] ==== 409 Conflict {rfc-status-409} {document} {POST} {PUT} {PATCH} {DELETE} [.indent] @@ -301,44 +287,39 @@ target resource. For example, you may get a {409} response when updating a resource that is older than the existing one on the server, resulting in a version control conflict. If this is used, it {MUST} be documented. For successful robust creation of resources ({PUT} or {POST}) you should always -return {200} or {204} and not {409}, even if the resource exists already. If any -`If-*` headers cause a conflict, you should use {412} and not {409}. Only +return {200} or {204} and not {409}, even if the resource exists already. If +any `If-*` headers cause a conflict, you should use {412} and not {409}. Only applicable to methods which change something. - [[status-code-410]] ==== 410 Gone {rfc-status-410} {do-not-document} {ALL} [.indent] -The resource does not exist any longer (but did exist in the past), and will -most likely not exist in the future. This can be used e.g. when accessing a +The resource does not exist any longer. It did exist in the past, and will +most likely not exist in the future. This can be used, e.g. when accessing a resource that has intentionally been deleted. This normally does not need to be documented, unless there is a specific need to distinguish this case from the normal {404}. - [[status-code-411]] ==== 411 Length Required {rfc-status-411} {document} {POST} {PUT} {PATCH} [.indent] -The server requires a {Content-Length} header for this request. This is normally -only relevant for large media uploads. The corresponding header parameter should -be marked as required. If used, it {MUST} to be documented (and explained). Only -applicable for methods with a request body. - +The server requires a {Content-Length} header for this request. This is +normally only relevant for large media uploads. The corresponding header +parameter should be marked as required. If used, it {MUST} to be documented +(and explained). [[status-code-412]] -==== 412 Precondition Failed {rfc-status-412} {do-not-document} {PUT} {PATCH} {DELETE} +==== 412 Precondition Failed {rfc-status-412} {use} {do-not-document} {PUT} {PATCH} {DELETE} [.indent] -Returned for conditional requests, e.g. {If-Match} if the condition failed. Used -for optimistic locking. Normally only applicable to methods that change +Returned for conditional requests, e.g. {If-Match} if the condition failed. +Used for optimistic locking. Normally only applicable to methods that change something. For {HEAD}/{GET} requests, use {304} instead. - [[status-code-415]] -==== 415 Unsupported Media Type {rfc-status-415} {do-not-document} {POST} {PUT} {PATCH} +==== 415 Unsupported Media Type {rfc-status-415} {use} {do-not-document} {POST} {PUT} {PATCH} [.indent] -The client did not provide a supported content-type for the request body. -Only applicable to methods with a request body. - +The client did not provide a supported content-type for the request body. Only +applicable to methods with a request body. [.do-not-use] [[status-code-417]] @@ -348,7 +329,6 @@ Returned when the client used an {Expect} header which the server does not support. The only defined value for the {Expect} header is very technical and does not belong in an API. - [.do-not-use] [[status-code-418]] ==== 418 I'm a teapot 🫖 (Unused) {rfc-status-418} {do-not-use} {ALL} @@ -357,7 +337,6 @@ Only use if you are implementing an API for a teapot that does not support brewing coffee. Response defined for April's Fools in https://www.rfc-editor.org/rfc/rfc2324.html[RFC 2324]. - [.do-not-use] [[status-code-422]] ==== 422 Unprocessable Content {rfc-status-422} {do-not-use} {ALL} @@ -366,21 +345,27 @@ The server understands the content type, but is unable to process the content. We do not recommend this code to be used as {400} already covers most use-cases and there does not seem to be a clear benefit to differentiating between them. - +[.do-not-use] [[status-code-423]] -==== 423 Locked {rfc-status-423} {PUT} {PATCH} {DELETE} +==== 423 Locked {rfc-status-423} {document} {PUT} {PATCH} {DELETE} [.indent] -Pessimistic locking, e.g. processing states. +Pessimistic locking, e.g. processing states. May be used to indicate an +existing resource lock, however, we recommend using optimistic locking instead. +If used, it must be documented to indicate pessimistic locking. +[.do-not-use] +[[status-code-424]] +==== 424 Failed Dependency {rfc-status-424} {do-not-use} {ALL} +[.indent] +The request failed due to failure of a previous request. This is not applicable +to restful APIs. [[status-code-428]] -==== 428 Precondition Required {rfc-status-428} {do-not-document} {ALL} +==== 428 Precondition Required {rfc-status-428} {use} {do-not-document} {ALL} [.indent] Server requires the request to be conditional, e.g. to make sure that the "lost -update problem" is avoided (see <<182>>). Instead of documenting this -response status, the required headers should be documented (and marked -as required). - +update problem" is avoided (see <<182>>). Instead of documenting this response +status, the required headers should be documented (and marked as required). [[status-code-429]] ==== 429 Too many requests {rfc-status-429} {use} {do-not-document} {ALL} @@ -388,31 +373,74 @@ as required). The client is not abiding by the rate limits in place and has sent too many requests (see <<153>>). +[[status-code-431]] +==== 431 Request Header Fields Too Large {rfc-status-431} {do-not-document} {ALL} +[.indent] +The server is not able to process the request because the request headers are +too large. Usually used by gateways and proxies with memory limits. + === Server side error codes [[status-code-500]] -==== 500 Internal Server Error {rfc-status-500} {do-not-document} {ALL} +==== 500 Internal Server Error {rfc-status-500} {use} {do-not-document} {ALL} [.indent] -A generic error indication for an unexpected server -execution problem (here, client retry may be sensible) - +A generic error indication for an unexpected server execution problem. Clients +should be careful with retrying on this response, since the nature of the +problem is unknown and must be expected to continue. [[status-code-501]] -==== 501 Not Implemented {rfc-status-501} {ALL} +==== 501 Not Implemented {rfc-status-501} {document} {ALL} +[.indent] +Server cannot fulfill the request, since the endpoint is not implemented yet. +Usually this implies future availability, but retrying now is not recommended. +May be documented on endpoints that are planned to be implemented in the +future to indicate that they are still not available. + +[[status-code-502]] +==== 502 Bad Gateway {rfc-status-502} {ALL} +[.indent]is meaningless +The server, while acting as a gateway or proxy, received an invalid response +from an inbound server attempting to fulfill the request. May be used by a +server to indicate that an inbound service is creating an unexpected result +instead of {500}. Clients should be careful with retrying on this response, +since the nature of the problem is unknown and must be expected to continue. + +[[status-code-503]] +==== 503 Service Unavailable {rfc-status-503} {use} {do-not-document} {ALL} [.indent] -Server cannot fulfill the request (usually implies future -availability, e.g. new feature). +Service is (temporarily) not available, e.g. if a required component or inbound +service is not available. Client are encouraged to retry requests following an +exponential back off pattern. If possible, the service should indicate how long +the client should wait by setting the {Retry-After} header. +[[status-code-504]] +==== 504 Gateway Timeout {rfc-status-504} {use} {ALL} +[.indent] +The server, while acting as a gateway or proxy, did not receive a timely +response. May be used by servers to indicate that an inbound service cannot +process the request fast enough. Client may retry the request immediately +exactly once, to check whether warming up the service solved the problem. -[[status-code-503]] -==== 503 Service Unavailable {rfc-status-503} {do-not-document} {ALL} +[.do-not-use] +[[status-code-505]] +==== 505 HTTP Version Not Supported {rfc-status-505} {do-not-use} {ALL} +[.indent] +The server does not support the HTTP protocol version used in the request. +Technical response code that serves not use case in RESTful APIs. + +[[status-code-507]] +==== 507 Insufficient Storage {rfc-status-507} {do-not-document} {POST} {PUT} {PATCH} [.indent] -Service is (temporarily) not available (e.g. if a -required component or downstream service is not available) -- client retry may -be sensible. If possible, the service should indicate how long the client -should wait by setting the {Retry-After} header. +The server is unable to store the resource as needed to complete the request. +May be used to indicate that the server is out of disk space. +[.do-not-use] +[[status-code-511]] +==== 511 Network Authentication Required {rfc-status-511} {do-not-use} {ALL} +[.indent] +The client needs to authenticate to gain network access. Technical response +code that serves no use case in RESTful APIs. [#220] @@ -523,7 +551,7 @@ The reason to allow both approaches is that APIs can have different needs. Retry-After is often sufficient for general load handling and request throttling scenarios and notably, does not strictly require the concept of a calling entity such as a tenant or named account. In turn -this allows resource owners to minimise the amount of state they have to +this allows resource owners to minimize the amount of state they have to carry with respect to client requests. The 'X-RateLimit' headers are suitable for scenarios where clients are associated with pre-existing account or tenancy structures. 'X-RateLimit' headers are generally @@ -593,7 +621,9 @@ identifiers in `type` and `instance` fields: *Hint:* The use of https://tools.ietf.org/html/rfc3986#section-4.3[absolute URIs] is not forbidden but strongly discouraged. If you use absolute URIs, -please reference https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.0.yaml#/Problem[problem-1.0.0.yaml#/Problem] instead. +please reference +https://opensource.zalando.com/restful-api-guidelines/models/problem-1.0.0.yaml#/Problem[problem-1.0.0.yaml#/Problem] +instead. [#177] @@ -612,10 +642,10 @@ for {304}, which is not really a redirection code). Usually you would use the redirection to migrate clients to a new service location. However, this is better accomplished by one of the following. -1. Changing the clients to use the new location in the first place, avoiding the -need for redirection. +1. Changing the clients to use the new location in the first place, avoiding + the need for redirection. 2. Redirecting the traffic behind the API layer (e.g. in the reverse proxy or -the app itself) without the client having to be involved. + the app itself) without the client having to be involved. 3. Deprecating the endpoint and removing it as described in <>. For idempotent {POST} cases, where you want to inform the client that a resource diff --git a/index.adoc b/index.adoc index d45352e5..928e802b 100644 --- a/index.adoc +++ b/index.adoc @@ -152,7 +152,10 @@ :429: pass:[429] :500: pass:[500] :501: pass:[501] +:502: pass:[502] :503: pass:[503] +:504: pass:[504] +:505: pass:[505] // See http-status-codes-and-errors.adoc for explanation :use: pass:quotes[link:#status-code-use[[.status-code-hint.should]#icon:check[] use#]]