Table of contents
API design principles
An important principle for API design and usage is Postel’s Law, aka The Robustness Principle (see also RFC 1122): Be liberal in what you accept, be conservative in what you send
Compatibility
MUST not break backward compatibility
Change APIs, but keep all consumers running. Consumers usually have independent release lifecycles, focus on stability, and avoid changes that do not provide additional value. APIs are contracts between service providers and service consumers that cannot be broken via unilateral decisions.
There are two techniques to change APIs without breaking them:
- follow rules for compatible extensions
- introduce new API versions and still support older versions
We strongly encourage using compatible API extensions and discourage versioning (see SHOULD avoid versioning and MUST use media type versioning below). The following guidelines for service providers (SHOULD prefer compatible extensions) and consumers (MUST prepare clients accept compatible API extensions) enable us (having Postel’s Law in mind) to make compatible changes without versioning.
Note: There is a difference between incompatible and breaking changes. Incompatible changes are changes that are not covered by the compatibility rules below. Breaking changes are incompatible changes deployed into operation, and thereby breaking running API consumers. Usually, incompatible changes are breaking changes when deployed into operation. However, in specific controlled situations it is possible to deploy incompatible changes in a non-breaking way, if no API consumer is using the affected API aspects (see also Deprecation guidelines).
Hint: Please note that the compatibility guarantees are for the « on the wire » format. Binary or source compatibility of code generated from an API definition is not covered by these rules. If client implementations update their generation process to a new version of the API definition, it has to be expected that code changes are necessary.
SHOULD avoid versioning
When changing your RESTful APIs, do so in a compatible way and avoid generating additional API versions. Multiple versions can significantly complicate understanding, testing, maintaining, evolving, operating and releasing our systems (supplementary reading)
If changing an API can’t be done in a compatible way, then proceed in one of these three ways:
- create a new resource (variant) in addition to the old resource variant
- create a new service endpoint — i.e. a new application with a new API (with a new domain name)
- create a new API version supported in parallel with the old API by the same microservice
As we discourage versioning by all means because of the manifold disadvantages, we strongly recommend to only use the first two approaches.
MUST use media type versioning
However, when API versioning is unavoidable, you have to design your multi-version RESTful APIs using media type versioning (see MUST not use URI versioning). Media type versioning is less tightly coupled since it supports content negotiation and hence reduces complexity of release management.
Version information and media type are provided together via the HTTP Content-Type
header — e.g. application/x.zalando.cart+json;version=2
. For incompatible changes, a new media type version for the resource is created. To generate the new representation version, consumer and producer can do content negotiation using the HTTP Content-Type
and Accept
headers.
Note
|
This versioning only applies to the request and response content schema, not to URI or method semantics. |
MUST not use URI versioning
With URI versioning a (major) version number is included in the path, e.g. /v1/customers
. The consumer has to wait until the provider has been released and deployed. If the consumer also supports hypermedia links — even in their APIs — to drive workflows (HATEOAS), this quickly becomes complex. So does coordinating version upgrades — especially with hyperlinked service dependencies — when using URL versioning. To avoid this tighter coupling and complexer release management we do not use URI versioning, and go instead with media type versioning and content negotiation (see above).
Custom media type format
Custom media type format should have the following pattern:
application/x.<custom-media-type>+json;version=<version>
-
custom-media-type
is a custom type name, e.g.zalando.cart
-
version
is a number, e.g.2
Example
In this example, a client wants only the new version of the response:
Accept: application/x.zalando.cart+json;version=2
A server responding to this, as well as a client sending a request with content should use the Content-Type
header, declaring that one is sending the new version:
Content-Type: application/x.zalando.cart+json;version=2
Using media type versioning should:
-
Use a custom media type, e.g.
application/x.zalando.cart+json
-
Include versions in request and response headers to increase visibility
-
Include
Content-Type
in theVary
header to enable proxy caches to differ between versions
Vary: Content-Type
Tip
|
Until an incompatible change is necessary, it is recommended to stay with the standard application/json media type and do not use media type versioning. |
Further reading: API Versioning Has No « Right Way » provides an overview on different versioning approaches to handle breaking changes without being opinionated.
Deprecation
Sometimes it is necessary to phase out an API endpoint, an API version, or an API feature, e.g. if a field or parameter is no longer supported or a whole business functionality behind an endpoint is supposed to be shut down. As long as the API endpoints and features are still used by consumers these shut downs are breaking changes and not allowed. To progress the following deprecation rules have to be applied to make sure that the necessary consumer changes and actions are well communicated and aligned using deprecation and sunset dates.
MUST obtain approval of clients before API shut down
Before shutting down an API, version of an API, or API feature the producer must make sure, that all clients have given their consent on a sunset date. Producers should help consumers to migrate to a potential new API or API feature by providing a migration manual and clearly state the time line for replacement availability and sunset (see also SHOULD add Deprecation
and Sunset
header to responses). Once all clients of a sunset API feature are migrated, the producer may shut down the deprecated API feature.
MUST collect external partner consent on deprecation time span
If the API is consumed by any external partner, the API owner must define a reasonable time span that the API will be maintained after the producer has announced deprecation. All external partners must state consent with this after-deprecation-life-span, i.e. the minimum time span between official deprecation and first possible sunset, before they are allowed to use the API.
MUST reflect deprecation in API specifications
The API deprecation must be part of the API specification.
If an API endpoint (operation object), an input argument (parameter object), an in/out data object (schema object), or on a more fine grained level, a schema attribute or property should be deprecated, the producers must set deprecated: true
for the affected element and add further explanation to the description
section of the API specification. If a future shut down is planned, the producer must provide a sunset date and document in details what consumers should use instead and how to migrate.
MUST monitor usage of deprecated API scheduled for sunset
Owners of an API, API version, or API feature used in production that is scheduled for sunset must monitor the usage of the sunset API, API version, or API feature in order to observe migration progress and avoid uncontrolled breaking effects on ongoing consumers. See also SHOULD monitor API usage.
SHOULD add Deprecation
and Sunset
header to responses
During the deprecation phase, the producer should add a Deprecation: <date-time>
(see draft: RFC Deprecation HTTP Header) and – if also planned – a Sunset: <date-time>
(see RFC 8594) header on each response affected by a deprecated element (see MUST reflect deprecation in API specifications).
The Deprecation
header can either be set to true
– if a feature is retired -, or carry a deprecation time stamp, at which a replacement will become/became available and consumers must not on-board any longer (see MUST not start using deprecated APIs). The optional Sunset
time stamp carries the information when consumers latest have to stop using a feature. The sunset date should always offer an eligible time interval for switching to a replacement feature.
Deprecation: Tue, 31 Dec 2024 23:59:59 GMT
Sunset: Wed, 31 Dec 2025 23:59:59 GMT
If multiple elements are deprecated the Deprecation
and Sunset
headers are expected to be set to the earliest time stamp to reflect the shortest interval consumers are expected to get active.
Note: adding the Deprecation
and Sunset
header is not sufficient to gain client consent to shut down an API or feature.
Hint: In earlier guideline versions, we used the Warning
header to provide the deprecation info to clients. However, Warning
header has a less specific semantics, will be obsolete with draft: RFC HTTP Caching, and our syntax was not compliant with RFC 7234 — Warning header.
SHOULD add monitoring for Deprecation
and Sunset
header
Clients should monitor the Deprecation
and Sunset
headers in HTTP responses to get information about future sunset of APIs and API features (see SHOULD add Deprecation
and Sunset
header to responses). We recommend that client owners build alerts on this monitoring information to ensure alignment with service owners on required migration task.
Hint: In earlier guideline versions, we used the Warning
header to provide the deprecation info (see hint in SHOULD add Deprecation
and Sunset
header to responses).
MUST not start using deprecated APIs
Clients must not start using deprecated APIs, API versions, or API features.
Compatibility
- MUST prepare clients accept compatible API extensions
- SHOULD used open-ended list of values (
x-extensible-enum
) for enumerations - SHOULD prefer compatible extensions
MUST use same semantics for null
and absent properties
Open API 3.x allows to mark properties as required
and as nullable
to specify whether properties may be absent ({}
) or null
({"example":null}
). If a property is defined to be not required
and nullable
(see 2nd row in Table below), this rule demands that both cases must be handled in the exact same manner by specification.
The following table shows all combinations and whether the examples are valid:
required | nullable | {} | {« example »:null} |
---|---|---|---|
|
|
✗ No |
✔ Yes |
|
|
✔ Yes |
|
|
|
✗ No |
✗ No |
|
|
✔ Yes |
✗ No |
While API designers and implementers may be tempted to assign different semantics to both cases, we explicitly decide against that option, because we think that any gain in expressiveness is far outweighed by the risk of clients not understanding and implementing the subtle differences incorrectly.
As an example, an API that provides the ability for different users to coordinate on a time schedule, e.g. a meeting, may have a resource for options in which every user has to make a choice
. The difference between undecided and decided against any of the options could be modeled as absent and null
respectively. It would be safer to express the null
case with a dedicated Null object, e.g. {}
compared to {"id":"42"}
.
Moreover, many major libraries have somewhere between little to no support for a null
/absent pattern (see Gson, Moshi, Jackson, JSON-B). Especially strongly-typed languages suffer from this since a new composite type is required to express the third state. Nullable Option
/Optional
/Maybe
types could be used but having nullable references of these types completely contradicts their purpose.
The only exception to this rule is JSON Merge Patch RFC 7396) which uses null
to explicitly indicate property deletion while absent properties are ignored, i.e. not modified.
JSON guidelines
- SHOULD represent enumerations as strings
- SHOULD declare enum values using one the following five conventions for capitalizing identifiers : Upper Snake case, Snake case, Pascal case, Camel case or Uppercase format about enum value naming conventions.
Snake case
The snake case is a typographical convention in computer science consisting of writing sets of words, usually in lowercase, separated by underscores. Here are several examples of writing variable names according to the original spelling:
- « variable name » becomes variable_name
- « TopCamelCaseVariableName » becomes name_of_variable_upper_camel_case
- « Variable » becomes variable
- « variable » becomes variable (no change)
Pascal case
The first letter in the identifier and the first letter of each subsequent concatenated word are capitalized. You can use Pascal case for identifiers of three or more characters. For example: PascalCase
Camel case
The camel case is a notation consisting of writing a set of words by linking them without spaces or punctuation, where the first letter of an identifier is lowercase and the first letter of each subsequent concatenated word is capitalized. For example: backColor.
This term refers to the hollows and bumps of a camel’s back represented by the alternation of lowercase and capitals
Uppercase
All letters in the identifier are capitalized. Use this convention only for identifiers that consist of two or fewer letters. For example: System.IO
System.Web.UI
Reference
https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-1.1/x2dbyw72(v=vs.71)?redirectedfrom=MSDN
http://gdt.oqlf.gouv.qc.ca/ficheOqlf.aspx?Id_Fiche=26543803
http://gdt.oqlf.gouv.qc.ca/ficheOqlf.aspx?Id_Fiche=26543805
https://fr.wikipedia.org/wiki/Snake_case
SHOULD prefer compatible extensions
API designers should apply the following rules to evolve RESTful APIs for services in a backward-compatible way:
- Enum ranges can be reduced when used as input parameters, only if the server is able to explain the reason (return an error) why the value is no longer allowed, eg dissolution of a country;
- Enum ranges can be extended when used for input parameters;
- Enum range can be reduced when used as output parameters;
- Enum ranges cannot be extended when used for output parameters — clients may not be prepared to handle it. Enums must be able to accept values of type ‘UNKNOWN’;
- Use x-extensible-enum, if range is used for output parameters and likely to be extended with growing functionality. It defines an open list of explicit values and clients must be agnostic to new values.
MUST prepare clients accept compatible API extensions
Service clients must be prepared for compatible API extensions of service providers:
- Be prepared that x-extensible-enum return parameter may deliver new values; either be agnostic or provide default behavior for unknown values.
SHOULD used open-ended list of values (x-extensible-enum
) for enumerations
- Enumerations are per definition closed sets of values, that are assumed to be complete and not intended for extension. This closed principle of enumerations imposes compatibility issues when an enumeration must be extended. To avoid these issues, we strongly recommend to use an open-ended list of values instead of an enumeration unless:
- the API has full control of the enumeration values, i.e. the list of values does not depend on any external tool or interface, and
- the list of value is complete with respect to any thinkable and unthinkable future feature.
- Examples : List of days, months, quarters, boolean (TRUE/FALSE)
To specify an open-ended list of values use the marker x-extensible-enum as follows:
delivery_methods:
type: string
x-extensible-enum:
– PARCEL
– LETTER
– EMAIL
default: EMAIL
description: Intended about delivery methodsNote: x-extensible-enum is not JSON Schema conform but will be ignored by most tools.
SHOULD represent enumerations as strings
Strings are a reasonable target for values that are by design enumerations.
MUST not use null for boolean properties
Schema based JSON properties that are by design booleans must not be presented as nulls. A boolean is essentially a closed enumeration of two values, true and false. If the content has a meaningful null value, strongly prefer to replace the boolean with enumeration of named values or statuses – for example accepted_terms_and_conditions with true or false can be replaced with terms_and_conditions with values yes, no and unknown.
MUST maintain backwards compatibility for events
Changes to events must be based around making additive and backward compatible changes. This follows the guideline, « Must: Don’t Break Backward Compatibility » from the Compatibility guidelines.
In the context of events, compatibility issues are complicated by the fact that producers and consumers of events are highly asynchronous and can’t use content-negotiation techniques that are available to REST style clients and servers. This places a higher bar on producers to maintain compatibility as they will not be in a position to serve versioned media types on demand.
For event schema, these are considered backward compatible changes, as seen by consumers –
- Adding new optional fields to JSON objects.
- Changing the order of fields (field order in objects is arbitrary).
- Changing the order of values with same type in an array.
- Removing optional fields.
- Removing an individual value from an enumeration.
These are considered backwards-incompatible changes, as seen by consumers –
- Removing required fields from JSON objects.
- Changing the default value of a field.
- Changing the type of a field, object, enum or array.
- Changing the order of values with different type in an array (also known as a tuple).
- Adding a new optional field to redefine the meaning of an existing field (also known as a co-occurrence constraint).
- Adding a value to an enumeration (note that x-extensible-enum is not available in JSON Schema)
Enums
You can use the enum
keyword to specify possible values of a request parameter or a model property. For example, the sort parameter in GET /items?sort=[asc|desc]
can be described as:
paths:
/items:
get:
parameters:
- in: query
name: sort
description: Sort order
schema:
type: string
enum: [asc, desc]
In YAML, you can also specify one enum value per line:
enum:
- asc
- desc
All values in an enum must adhere to the specified type
. If you need to specify descriptions for enum items, you can do this in the description
of the parameter or property:
parameters:
- in: query
name: sort
schema:
type: string
enum: [asc, desc]
description: >
Sort order:
* `asc` - Ascending, from A to Z
* `desc` - Descending, from Z to A
Nullable enums
A nullable enum can be defined as follows:
type: string
nullable: true # <---
enum:
- asc
- desc
- null # <--- without quotes, i.e. null not "null"
Note that null
must be explicitly included in the list of enum
values. Using nullable: true
alone is not enough here.
Reusable enums
In OpenAPI 3.0, both operation parameters and data models use a schema
, making it easy to reuse the data types. You can define reusable enums in the global components
section and reference them via $ref
elsewhere.
paths:
/products:
get:
parameters:
- in: query
name: color
required: true
schema:
$ref: '#/components/schemas/Color'
responses:
'200':
description: OK
components:
schemas:
Color:
type: string
enum:
- black
- white
- red
- green
- blue
Specification Extensions
While the OpenAPI Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points.
The extensions properties are implemented as patterned fields that are always prefixed by « x-« .
Field Pattern | Type | Description |
---|---|---|
^x- | Any | Allows extensions to the OpenAPI Schema. The field name MUST begin with x-, for example, x-internal-id. The value can be null, a primitive, an array or an object. Can have any valid JSON format value. |
The extensions may or may not be supported by the available tooling, but those may be extended as well to add requested support (if tools are internal or open-sourced).
RESTful API guidelines
Organization https://developers.google.com/s/results/assistant/conversational/overview?q=enum%20frozen This enum is not yet frozen and values maybe added later. https://tvh-equipment.gitlab.io/api-guidelines/index.html TVH Equipment, fabricant de nacelles élévatrices de Belgique, fait partie du groupe mateco (avec plus de 60 sites en Europe et même plus de 80 partenaires dans le monde). . https://opensource.zalando.com/restful-api-guidelines/# https://github.com/zalando/restful-api-guidelines Zalando est une entreprise de commerce électronique allemande, spécialisée dans la vente de chaussures et de vêtements, basée à Berlin. Créée en 2008 par Rocket Internet, elle est présente dans 17 pays européens https://cobra.netapp.com/guide/#Fondée en 1992, NetApp a profité de la croissance liée à Internet dans les années 1999-2001. Elle compte à présent plus de 10 000 employés dans le monde, et conçoit des solutions dans le domaine du stockage informatique en proposant des baies disque https://schweizerischebundesbahnen.github.io/api-principles/ https://github.com/schweizerischebundesbahnen/api-principles Les Chemins de fer fédéraux suisses (CFF); en allemand Schweizerische Bundesbahnen (SBB) ; en italien Ferrovie Federali Svizzere (FFS) ; en romanche Viafiers federalas svizras (VFS) ou (VFF) sont la principale compagnie ferroviaire de Suisse. https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md The OpenAPI Initiative (OAI) was created by a consortium of forward-looking industry experts who recognize the immense value of standardizing on how APIs are described. As an open governance structure under the Linux Foundation, the OAI is focused on creating, evolving and promoting a vendor neutral description format. The OpenAPI Specification was originally based on the Swagger Specification, donated by SmartBear Software.http://www.withouthaste.com/codeNotes/rest.php#header1 |
|