When passing procedure parameters on the stack why are the following lines of code often necessary in a procedure?

The simplest technique is to simply store the information in various registers. IOASM uses this technique, where the information is stored in the AX register. The advantage of using this technique is that information in the registers can be immediately used, and the code is simpler and faster. The disadvantage is that the registers restrict the number of parameters and they become tied up once a value is stored in a particular register. Also, once a procedure is written to use a particular register, every calling routine must set the parameter in that same register, irrespective of whether it is in use or not.

The more general technique is to use the stack to store parameters. The advantage is that there are no restrictions to size or register usage. The disadvantage is that the code becomes a bit more complex.

Parameter-Passing using the Stack

Before calling a procedure, all its parameters must be stored on the stack.

push ax
push bx
call testproc

The procedure can now access these variables on the stack. Recall that the stack pointer (SP - register) points to the topmost element on the stack. After calling a procedure, this is normally the return address. Thus, the first parameter (or rather, the last parameter pushed) is at SP+2. To access this parameter (value of BX in the above example), the address [SP+2] can be used. This follows the conventions of addressing as discussed in chapter 2, so is perfectly legal. The second parameter (AX) can be accessed using the address [SP+4].

The only problem with this approach is that the SP register's value will change if the stack is used within the procedure. Thus it may be better to note the value at the start of the program and use this value for parameter references. The value can be stored in the BP (base pointer) register. Thus references can be made relative to the BP register, viz. [BP+2] and [BP+4]. The code for the procedure will therefore look like:

testproc PROC
mov bp,sp
...
mov sp,bp
ret
testproc ENDP

The first MOV statement sets up the BP register with the initial value of the SP register. The last statement in the procedure will restore the stack if it wasn't cleared up properly within the procedural code.

This is still fallible because the BP register could be storing an important value. Suppose that one procedure calls another procedure. It would be quite disastrous because the second procedure would destroy the BP register and the first procedure would not be able to regain its value. It makes a lot of sense to save the BP register before calling a procedure and restore it afterwards. But this would mean two extra lines of code for every procedure call. Instead, its better to save the BP register at the top of the procedure code and restore it at the bottom.

testproc PROC
push bp
mov bp,sp
...
mov sp,bp
pop bp
ret
testproc ENDP

Of course, since there is now one extra element on the stack, all parameter references must be shifted by one position. Thus, the value of BX (as per the example) is now at [BP+4] and AX is at [BP+6]. Any number of variables can be stored on the stack in a similar manner. For all cases the last word will be located at [BP+4], the previous one at [BP+6], etc..

After calling the procedure, it is also necessary to clear the parameters off the stack. Instead of putting in a number of POP statements after every procedure call, the RET instruction has a mechanism to automatically kill the parameters after returning to the calling code. If a single constant integer parameter is specified, then those number of bytes will be popped off the stack when the procedure returns. In the example above, there are two word parameters which take up four bytes, so the last instruction in the procedure would be

If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

Register indirect addressing is accessing memory through an address stored in a register.
mov esi, OFFSET list
mov eax, [esi]
add esi, 4
mov eax, [esi]

Indexed addressing is adding a constant to a register to generate an effective address.
mov esi, 0
mov eax, list[esi] ; or [list + esi]

Base Indexed Addressing is accessing lists through the base pointer in procedures.
mov esi, [ebp + 12] ; @list
mov edx, 0
mov eax, [esi + edx] ; gets curr element

Zalando’s software architecture centers around decoupled microservices that provide functionality via RESTful APIs with a JSON payload. Small engineering teams own, deploy and operate these microservices in their AWS (team) accounts. Our APIs most purely express what our systems do, and are therefore highly valuable business assets. Designing high-quality, long-lasting APIs has become even more critical for us since we started developing our new open platform strategy, which transforms Zalando from an online shop into an expansive fashion platform. Our strategy emphasizes developing lots of public APIs for our external business partners to use via third-party applications.

With this in mind, we’ve adopted "API First" as one of our key engineering principles. Microservices development begins with API definition outside the code and ideally involves ample peer-review feedback to achieve high-quality APIs. API First encompasses a set of quality-related standards and fosters a peer review culture including a lightweight review procedure. We encourage our teams to follow them to ensure that our APIs:

  • are easy to understand and learn

  • are general and abstracted from specific implementation and use cases

  • are robust and easy to use

  • have a common look and feel

  • follow a consistent RESTful style and syntax

  • are consistent with other teams’ APIs and our global architecture

Ideally, all Zalando APIs will look like the same author created them.

The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in this document (case insensitive) are to be interpreted as described in RFC 2119.

The purpose of our "RESTful API guidelines" is to define standards to successfully establish "consistent API look and feel" quality. The API Guild (internal_link) drafted and owns this document. Teams are responsible to fulfill these guidelines during API development and are encouraged to contribute to guideline evolution via pull requests.

These guidelines will, to some extent, remain work in progress as our work evolves, but teams can confidently follow and trust them.

In case guidelines are changing, following rules apply:

  • existing APIs don’t have to be changed, but we recommend it

  • clients of existing APIs have to cope with these APIs based on outdated rules

  • new APIs have to respect the current guidelines

Furthermore you should keep in mind that once an API becomes public externally available, it has to be re-reviewed and changed according to current guidelines - for sake of overall consistency.

Comparing SOA web service interfacing style of SOAP vs. REST, the former tend to be centered around operations that are usually use-case specific and specialized. In contrast, REST is centered around business (data) entities exposed as resources that are identified via URIs and can be manipulated via standardized CRUD-like methods using different representations, and hypermedia. RESTful APIs tend to be less use-case specific and come with less rigid client / server coupling and are more suitable for an ecosystem of (core) services providing a platform of APIs to build diverse new business services. We apply the RESTful web service principles to all kind of application (micro-) service components, independently from whether they provide functionality via the internet or intranet.

  • We prefer REST-based APIs with JSON payloads

  • We prefer systems to be truly RESTful []

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

Readings: Some interesting reads on the RESTful API design style and service architecture:

  • Article: REST API Design - Resource Modeling

  • Article: Richardson Maturity Model — Steps toward the glory of REST

  • Book: Irresistible APIs: Designing web APIs that developers will love

  • Book: REST in Practice: Hypermedia and Systems Architecture

  • Book: Build APIs You Won’t Hate

  • Fielding Dissertation: Architectural Styles and the Design of Network-Based Software Architectures

As mentioned above, Zalando is transforming from an online shop into an expansive fashion platform comprising a rich set of products following a Software as a Platform (SaaP) model for our business partners. As a company we want to deliver products to our (internal and external) customers which can be consumed like a service.

Platform products provide their functionality via (public) APIs; hence, the design of our APIs should be based on the API as a Product principle:

  • Treat your API as product and act like a product owner

  • Put yourself into the place of your customers; be an advocate for their needs

  • Emphasize simplicity, comprehensibility, and usability of APIs to make them irresistible for client engineers

  • Actively improve and maintain API consistency over the long term

  • Make use of customer feedback and provide service level support

Embracing 'API as a Product' facilitates a service ecosystem, which can be evolved more easily and used to experiment quickly with new business ideas by recombining core capabilities. It makes the difference between agile, innovative product service business built on a platform of APIs and ordinary enterprise integration business where APIs are provided as "appendix" of existing products to support system integration and optimised for local server-side realization.

Understand the concrete use cases of your customers and carefully check the trade-offs of your API design variants with a product mindset. Avoid short-term implementation optimizations at the expense of unnecessary client side obligations, and have a high attention on API quality and client developer experience.

API as a Product is closely related to our (see next chapter) which is more focused on how we engineer high quality APIs.

API First is one of our engineering and architecture principles. In a nutshell API First requires two aspects:

  • define APIs first, before coding its implementation, using a standard specification language

  • get early review feedback from peers and client developers

By defining APIs outside the code, we want to facilitate early review feedback and also a development discipline that focus service interface design on…​

  • profound understanding of the domain and required functionality

  • generalized business entities / resources, i.e. avoidance of use case specific APIs

  • clear separation of WHAT vs. HOW concerns, i.e. abstraction from implementation aspects — APIs should be stable even if we replace complete service implementation including its underlying technology stack

Moreover, API definitions with standardized specification format also facilitate…​

  • single source of truth for the API specification; it is a crucial part of a contract between service provider and client users

  • infrastructure tooling for API discovery, API GUIs, API documents, automated quality checks

Elements of API First are also this API Guidelines and a standardized API review process as to get early review feedback from peers and client developers. Peer review is important for us to get high quality APIs, to enable architectural and design alignment and to supported development of client applications decoupled from service provider engineering life cycle.

It is important to learn, that API First is not in conflict with the agile development principles that we love. Service applications should evolve incrementally — and so its APIs. Of course, our API specification will and should evolve iteratively in different cycles; however, each starting with draft status and early team and peer review feedback. API may change and profit from implementation concerns and automated testing feedback. API evolution during development life cycle may include breaking changes for not yet productive features and as long as we have aligned the changes with the clients. Hence, API First does not mean that you must have 100% domain and requirement understanding and can never produce code before you have defined the complete API and get it confirmed by peer review.

On the other hand, API First obviously is in conflict with the bad practice of publishing API definition and asking for peer review after the service integration or even the service productive operation has started. It is crucial to request and get early feedback — as early as possible, but not before the API changes are comprehensive with focus to the next evolution step and have a certain quality (including API Guideline compliance), already confirmed via team internal reviews.

The titles are marked with the corresponding labels: MUST, SHOULD, MAY.

You must follow the , more specifically:

  • You must define APIs first, before coding its implementation,

  • You must design your APIs consistently with these guidelines; use our API Linter Service (internal_link) for automated rule checks.

  • You must call for early review feedback from peers and client developers, and apply our lightweight API review process (internal_link) for all component external APIs, i.e. all apis with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.11 (see ).

We use the OpenAPI specification as standard to define API specification files. API designers are required to provide the API specification using a single self-contained YAML file to improve readability. We encourage to use OpenAPI 3.0 version, but still support OpenAPI 2.0 (a.k.a. Swagger 2).

The API specification files should be subject to version control using a source code management system - best together with the implementing sources.

You the component API specification with the deployment of the implementing service, and, hence, make it discoverable for the group via our API Portal (internal_link).

Hint: A good way to explore OpenAPI 3.0/2.0 is to navigate through the OpenAPI specification mind map and use our Swagger Plugin for IntelliJ IDEA to create your first API. To explore and validate/evaluate existing APIs the Swagger Editor or our API Portal may be a good starting point.

Hint: We do not yet provide guidelines for GraphQL and focus on resource oriented HTTP/REST API style (and related tooling and infrastructure support). Following our Zalando Tech Radar (internal_link), we think that GraphQL has no major benefits, but a couple of downsides compared to REST as API technology for general purpose peer-to-peer microservice communication. However, GraphQL can provide a lot of value for specific target domain problems, especially backends for frontends (BFF) and mobile clients, where typically many (domain object) resources from different services are queried and multiple roundtrip overhead should be avoided due to (mobile or public) network constraints. Therefore we list both technologies on ADOPT, though GraphQL only supplements REST for the BFF-specific problem domain.

In addition to the API Specification, it is good practice to provide an API user manual to improve client developer experience, especially of engineers that are less experienced in using this API. A helpful API user manual typically describes the following API aspects:

  • API scope, purpose, and use cases

  • concrete examples of API usage

  • edge cases, error situation details, and repair hints

  • architecture context and major dependencies - including figures and sequence flows

The user manual must be published online, e.g. via our documentation hosting platform service, GHE pages, or specific team web servers. Please do not forget to include a link to the API user manual into the API specification using the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.12 property.

Normally, API specification files must be self-contained, i.e. files should not contain references to local or remote content, e.g. /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.13 or /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.14. The reason is, that the content referred to is in general not durable and not immutable. As a consequence, the semantic of an API may change in unexpected ways. (For example, the second link is already outdated due to code restructuring.)

However, you may use remote references to resources accessible by the following service URLs:

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.15 – used to refer to user-defined, immutable API specification revisions published via the internal API repository.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.16 – used to refer to guideline-defined re-usable API fragments (see /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.17 files in restful-api-guidelines/models for details).

Hint: The formerly used remote references to the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.18 API fragment (aliases /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.19 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.20) are deprecated, but still supported for compatibility ( on how to replace).

As we control these URLs, we ensure that their content is durable and immutable. This allows to define API specifications by using fragments published via these sources, as suggested in .

API specifications must contain the following OpenAPI meta information to allow for API management:

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.21 as (unique) identifying, functional descriptive name of the API

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.22 to distinguish API specifications versions following

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.23 containing a proper description of the API

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.24 containing the responsible team

Following OpenAPI extension properties must be provided in addition:

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.25 unique identifier of the API ()

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.26 intended target audience of the API ()

OpenAPI allows to specify the API specification version in /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.22. To share a common semantic of version information we expect API designers to comply to Semantic Versioning 2.0 rules /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.28 to /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.29 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.30 restricted to the format <MAJOR>.<MINOR>.<PATCH> for versions as follows:

  • Increment the MAJOR version when you make incompatible API changes after having aligned the changes with consumers,

  • Increment the MINOR version when you add new functionality in a backwards-compatible manner, and

  • Optionally increment the PATCH version when you make backwards-compatible bug fixes or editorial changes not affecting the functionality.

Additional Notes:

  • Pre-release versions () and build metadata () must not be used in API version information.

  • While patch versions are useful for fixing typos etc, API designers are free to decide whether they increment it or not.

  • API designers should consider to use API version /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.31 () for initial API design.

Example:

openapi: 3.0.1 info: title: Parcel Service API description: API for <...> version: 1.3.7 <...>

Each API specification must be provisioned with a globally unique and immutable API identifier. The API identifier is defined in the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.32-block of the OpenAPI specification and must conform to the following definition:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.

API specifications will evolve and any aspect of an OpenAPI specification may change. We require API identifiers because we want to support API clients and providers with API lifecycle management features, like change trackability and history or automated backward compatibility checks. The immutable API identifier allows the identification of all API specification versions of an API evolution. By using or as order criteria you get the version or publication history as a sequence of API specifications.

Note: While it is nice to use human readable API identifiers based on self-managed URNs, it is recommend to stick to UUIDs to relief API designers from any urge of changing the API identifier while evolving the API. Example:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>

Each API must be classified with respect to the intended target audience supposed to consume the API, to facilitate differentiated standards on APIs for discoverability, changeability, quality of design and documentation, as well as permission granting. We differentiate the following API audience groups with clear organisational and legal boundaries:

component-internal

This is often referred to as a team internal API or a product internal API. The API consumers with this audience are restricted to applications of the same functional component which typically represents a specific product with clear functional scope and ownership. All services of a functional component / product are owned by a specific dedicated owner and engineering team(s). Typical examples of component-internal APIs are APIs being used by internal helper and worker services or that support service operation.

business-unit-internal

The API consumers with this audience are restricted to applications of a specific product portfolio owned by the same business unit.

company-internal

The API consumers with this audience are restricted to applications owned by the business units of the same the company (e.g. Zalando company with Zalando SE, Zalando Payments SE & Co. KG. etc.)

external-partner

The API consumers with this audience are restricted to applications of business partners of the company owning the API and the company itself.

external-public

APIs with this audience can be accessed by anyone with Internet access.

Note: a smaller audience group is intentionally included in the wider group and thus does not need to be declared additionally.

The API audience is provided as API meta information in the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.32-block of the OpenAPI specification and must conform to the following specification:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.

Note: Exactly one audience per API specification is allowed. For this reason a smaller audience group is intentionally included in the wider group and thus does not need to be declared additionally. If parts of your API have a different target audience, we recommend to split API specifications along the target audience — even if this creates redundancies (rationale (internal_link)).

Example:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>

For details and more information on audience groups see the API Audience narrative (internal_link).

Functional naming is a powerful, yet easy way to align global resources as host, permission, and event names within an application landscape. It helps to preserve uniqueness of names while giving readers meaningful context information about the addressed component. Besides, the most important aspect is, that it allows to keep APIs stable in the case of technical and organizational changes (Zalando for example maintains an internal naming convention).

A unique /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.34 is assigned to each functional component serving an API. It is built of the domain name of the functional group the component is belonging to and a unique a short identifier for the functional component itself:

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component

Depending on the , you must/should/may follow the functional naming schema for and (and also , in future) as follows:

Functional Naming

Audience

must

external-public, external-partner

should

company-internal, business-unit-internal

may

component-internal

Please see the following rules for detailed functional naming patterns: * *

Internal Guideance: You must use the simple functional name registry (internal_link) to register your functional name before using it. The registry is a centralized infrastructure service to ensure uniqueness of your functional names (and available domains — including subdomains) and to support hostname DNS resolution.
Hint: Due to lexicalic restrictions of DNS names there is no specific separator to split a functional name into (sub) domain and component; this knowledge is only managed in the registry.

Hostnames in APIs must, respectively should conform to the functional naming depending on the as follows (see for details and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.35 definition):

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com

Hint: The following convention (e.g. used by legacy STUPS infrastructure) is deprecated and only allowed for hostnames of APIs:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier

Exception: There are legacy hostnames used for APIs with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.36 audience which may not follow this rule due to backward compatibility constraints. The API Linter maintains an allow-list for these exceptions (including e.g. /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.37 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.38).

Every API endpoint must be protected and armed with authentication and authorization. As part of the API definition you must specify how you protect your API using either the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.39 typed /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.40 or /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.41 typed security schemes defined in the OpenAPI Authentication Specification.

The majority of our APIs (especially the company internal APIs) are protected using JWT tokens provided by the platform IAM token service. In these situations you should use the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.39 typed Bearer Authentication security scheme — it is based on OAuth2.0 RFC 6750 defining the standard header /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.43. The following code snippet shows how to define the bearer security scheme.

components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT

The bearer security schema can then be applied to all API endpoints, e.g. requiring the token to have /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.44 scope for permission as follows (see also ):

security: - BearerAuth: [ api-repository.read ]

In other, more specific situations e.g. with customer and partner facing APIs you may use other OAuth 2.0 authorization flows as defined by RFC 6749. Please consult the OpenAPI OAuth 2.0 Authentication section for details on how to define /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.41 typed security schemes correctly.

Note: Do not use OpenAPI /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.41 typed security scheme flows (e.g. /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.47) if your service does not fully support it and implements a simple bearer token scheme, because it exposes authentication server address details and may make use of redirection.

APIs must define permissions to protect their resources. Thus, at least one permission must be assigned to each API endpoint.

The naming schema for permissions corresponds to the naming schema for and . Please refer to for designing permission names and see the following examples.

Application IDResource IDAccess TypeExample

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.48

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.49

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.50

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.51

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.48

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.53

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.50

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.55

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.56

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.57

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.58

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.59

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.50

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.61

Note: APIs should stick to component specific permissions without resource extension to avoid the complexity of too many fine grained permissions. For the majority of use cases, restricting access for specific API endpoints using read or write is sufficient.

The defined permissions are than assigned to each API endpoint based on the security schema (see example in ) by specifying the as follows:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.0

In some cases a whole API or selected API endpoints may not require specific permissions, e.g. if information is public or protected by object level authorization. To make this explicit you should assign the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.62 pseudo permission, that is always available as OAuth2 default scope in Zalando.

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.1

Hint: Following a minimal a minimal API specification approach, the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.63-header does not need to be defined on each API endpoint, since it is required and so to say implicitly defined via the security section.

As long as the is not yet supported by our permission registry, permission names in APIs must conform to the following naming pattern:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.2

This pattern is compatible with the previous definition.

(based on ) defines formats from ISO and IETF standards for date/time, integers/numbers and binary data. You must use these formats, whenever applicable:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.64/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.65SpecificationExample

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.66

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.67

4 byte signed integer between -231 and 231-1

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.68

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.66

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.70

8 byte signed integer between -263 and 263-1

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.71

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.66

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.73

arbitrarily large signed integer number

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.74

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.75

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.76

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.77 single precision decimal number — see IEEE 754-2008/ISO 60559:2011

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.78

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.75

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.80

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.81 double precision decimal number — see IEEE 754-2008/ISO 60559:2011

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.82

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.75

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.84

arbitrarily precise signed decimal number

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.85

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.87

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.88 encoded byte following

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.89

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.91

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.88 encoded byte sequence following

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.93

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.95

RFC 3339 internet profile — subset of

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.96

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.98

RFC 3339 internet profile — subset of

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.99

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>01

RFC 3339 internet profile — subset of

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>02

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>04

RFC 3339 internet profile — subset of

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>05

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>07

RFC 3339 internet profile — subset of

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>08

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>10

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>11

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>13

RFC 5322

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>14

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>16

RFC 6531

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>17

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>19

RFC 1034

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>20

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>22

RFC 5890

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>23

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>25

RFC 2673

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>26

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>28

RFC 4291

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>29

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>31

RFC 3986

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>32

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>34

RFC 3986

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>35

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>37

RFC 6570

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>38

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>40

RFC 3987

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>41

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>43

RFC 3987

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>44

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

RFC 4122

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>47

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>49

RFC 6901

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>50

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>52

Relative JSON pointers

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>53

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>55

regular expressions as defined in ECMA 262

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>56

Note: Formats /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.73 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.84 have been added to the OpenAPI defined formats — see also and below.

We add further OpenAPI formats that are useful especially in an e-commerce environment e.g. openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>59, openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>60, and openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>61 based other ISO and IETF standards. You must use these formats, whenever applicable:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.64openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>63SpecificationExample

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>65

two letter language code — see ISO 639-1. Hint: In the past we used openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>66 as format.

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>67

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>69

multi letter language tag — see BCP 47. It is a compatible extension of ISO 639-1 optionally with additional information for language usage, like region, variant, script.

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>70

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>72

two letter country code — see ISO 3166-1 alpha-2. Hint: In the past we used openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>73 as format.

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>74 Hint: It is openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>74, not openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>76, even though openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>76 has seen some use at Zalando.

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>79

three letter currency code — see ISO 4217

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>80

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>82

Global Trade Item Number — see GTIN

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>83

Remark: Please note that this list of standard data formats is not exhaustive and everyone is encouraged to propose additions.

In we added /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.73 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.84 to the OpenAPI defined formats. As an implication, you must always provide one of the formats /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.67, /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.70, /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.73 or /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.76, /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.80, /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.84 when you define an API property of JSON type /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.75 or /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.66.

By this we prevent clients from guessing the precision incorrectly, and thereby changing the value unintentionally. The precision must be translated by clients and servers into the most specific language types; in Java, for instance, the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.75 type with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.84 format will translate into openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>96 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.66 type with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.67 format will translate to openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>99 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.00 Java types.

You may expose binary data. You must use a standard media type and data format, if applicable — see . If no standard is available, you must define the binary data as /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86 typed property with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.91 format using /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.88 encoding — as also described in .

As a specific case of , you must use the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86 typed formats /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.95, /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.98, openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>01, openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>04, or openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>07 for the definition of date and time properties. The formats are based on the standard RFC 3339 internet profile -- a subset of

Exception: For passing date/time information via standard protocol headers, HTTP requires to follow the date and time specification used by the Internet Message Format RFC 5322.

As defined by the standard, time zone offset may be used, however, we recommend to only use times based on UTC without local offsets. For example /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.11 rather than /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.12. From experience we have learned that zone offsets are not easy to understand and often not correctly handled. Note also that zone offsets are different from local times which may include daylight saving time. When it comes to storage, all dates should be consistently stored in UTC without a zone offset. Localization should be done locally by the services that provide user interfaces, if required.

Hint: We discourage using numerical timestamps. It typically creates issues with precision, e.g. whether to represent a timestamp as 1460062925, 1460062925000 or 1460062925.000. Date strings, though more verbose and requiring more effort to parse, avoid this ambiguity.

Properties and that are by design durations and time intervals should be represented as strings formatted as defined by ISO 8601 ( for /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.13 and /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.14 - the latter called time intervals in ISO 8601). ISO 8601:1-2019 defines an extension (/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.15) to express open ended time intervals that are very convenient in searches and are included in the below ABNF grammar:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.3

A time interval query parameters should use /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.16 instead of the parameter tuple /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.17//info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.18, while properties providing a time interval should be named /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.19.

As a specific case of you must use the following standard formats:

  • Country codes: ISO 3166-1-alpha-2 two letter country codes indicated via format openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>72 in the OpenAPI specification.

  • Language codes: ISO 639-1 two letter language codes indicated via format openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>65 in the OpenAPI specification.

  • Language variant tags: BCP 47 multi letter language tag indicated via format openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>69 in the OpenAPI specification. (It is a compatible extension of ISO 639-1 with additional optional information for language usage, like region, variant, script)

  • Currency codes: ISO 4217 three letter currency codes indicated via format openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>79 in the OpenAPI specification.

In some situations the API supports serving different representations of a specific resource (at the same URL), e.g. JSON, PDF, TEXT, or HTML representations for an invoice resource. You should use content negotiation to support clients specifying via the standard HTTP headers , , which representation is best suited for their use case, for example, which language of a document, representation / content format, or content encoding. You like /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.27 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.28 for defining the content format in the header.

Generating IDs can be a scaling problem in high frequency and near real time use cases. UUIDs solve this problem, as they can be generated without collisions in a distributed, non-coordinated way and without additional server round trips.

However, they also come with some disadvantages:

  • pure technical key without meaning; not ready for naming or name scope conventions that might be helpful for pragmatic reasons, e.g. we learned to use names for product attributes, instead of UUIDs

  • less usable, because…​

    • cannot be memorized and easily communicated by humans

    • harder to use in debugging and logging analysis

    • less convenient for consumer facing usage

  • quite long: readable representation requires 36 characters and comes with higher memory and bandwidth consumption

  • not ordered along their creation history and no indication of used id volume

  • may be in conflict with additional backward compatibility support of legacy ids

UUIDs should be avoided when not needed for large scale id generation. Instead, for instance, server side support with id generation can be preferred ( on id resource, followed by idempotent on entity resource). Usage of UUIDs is especially discouraged as primary keys of master and configuration data, like brand-ids or attribute-ids which have low id volume but widespread steering functionality.

Please be aware that sequential, strictly monotonically increasing numeric identifiers may reveal critical, confidential business information, like order volume, to non-privileged clients.

In any case, we should always use string rather than number type for identifiers. This gives us more flexibility to evolve the identifier naming scheme. Accordingly, if used as identifiers, UUIDs should not be qualified using a format property.

Hint: Usually, random UUID is used - see UUID version 4 in RFC 4122. Though UUID version 1 also contains leading timestamps it is not reflected by its lexicographic sorting. This deficit is addressed by ULID (Universally Unique Lexicographically Sortable Identifier). You may favour ULID instead of UUID, for instance, for pagination use cases ordered along creation time.

Guidelines for naming and designing resource paths and query parameters.

In most cases, all resources provided by a service are part of the public API, and therefore should be made available under the root "/" base path.

If the service should also support non-public, internal APIs — for specific operational support functions, for example — we encourage you to maintain two different API specifications and provide . For both APIs, you should not use /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.32 as base path.

We see API’s base path as a part of deployment variant configuration. Therefore, this information has to be declared in the .

Usually, a collection of resource instances is provided (at least the API should be ready here). The special case of a resource singleton must be modeled as a collection with cardinality 1 including definition of /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.33 = /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.34 = 1 for the returned /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.35 structure to make the cardinality constraint explicit.

Exception: the pseudo identifier /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.36 used to specify a resource endpoint where the resource identifier is provided by authorization information (see ).

To simplify encoding of resource IDs in URLs they must match the regex /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.37. Resource IDs only consist of ASCII strings using letters, numbers, underscore, minus, colon, period, and - on rare occasions - slash.

Note: slashes are only allowed to build and signal resource identifiers consisting of .

Note: to prevent ambiguities of resource identifiers must never be empty. Consequently, support of empty strings for path parameters is forbidden.

Path segments are restricted to ASCII kebab-case strings matching regex /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.38. The first character must be a lower case letter, and subsequent characters can be a letter, or a dash(/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.39), or a number.

Example:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.4

Hint: kebab-case applies to concrete path segments and not necessarily the names of path parameters.

You must not specify paths with duplicate or trailing slashes, e.g. /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.40 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.41. As a consequence, you must also not specify or use path variables with empty string values.

Note: Non standard paths have no clear semantics. As a result, behavior for non standard paths varies between different HTTP infrastructure components and libraries. This may leads to ambiguous and unexpected results during request handling and monitoring.

We recommend to implement services robust against clients not following this rule. All services should normalize request paths before processing by removing duplicate and trailing slashes. Hence, the following requests should refer to the same resource:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.5

Note: path normalization is not supported by all framework out-of-the-box. Services are required to support at least the normalized path while rejecting all alternatives paths, if failing to deliver the same resource.

The API describes resources, so the only place where actions should appear is in the HTTP methods. In URLs, use only nouns. Instead of thinking of actions (verbs), it’s often helpful to think about putting a message in a letter box: e.g., instead of having the verb cancel in the url, think of sending a message to cancel an order to the cancellations letter box on the server side.

REST is all about your resources, so consider the domain entities that take part in web service interaction, and aim to model your API around these using the standard HTTP methods as operation indicators. For instance, if an application has to lock articles explicitly so that only one user may edit them, create an article lock with or instead of using a lock action.

Request:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.6

The added benefit is that you already have a service for browsing and filtering article locks.

As a rule of thumb resources should be defined to cover 90% of all its client’s use cases. A useful resource should contain as much information as necessary, but as little as possible. A great way to support the last 10% is to allow clients to specify their needs for more/less information by supporting filtering and .

API resources represent elements of the application’s domain model. Using domain-specific nomenclature for resource names helps developers to understand the functionality and basic semantics of your resources. It also reduces the need for further documentation outside the API definition. For example, "sales-order-items" is superior to "order-items" in that it clearly indicates which business object it represents. Along these lines, "items" is too general.

An API should contain the complete business processes containing all resources representing the process. This enables clients to understand the business process, foster a consistent design of the business process, allow for synergies from description and implementation perspective, and eliminates implicit invisible dependencies between APIs.

In addition, it prevents services from being designed as thin wrappers around databases, which normally tends to shift business logic to the clients.

Some API resources may contain or reference sub-resources. Embedded sub-resources, which are not top-level resources, are parts of a higher-level resource and cannot be used outside of its scope. Sub-resources should be referenced by their name and identifier in the path segments as follows:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.7

In order to improve the consumer experience, you should aim for intuitively understandable URLs, where each sub-path is a valid reference to a resource or a set of resources. For instance, if /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.44 is valid, then, in principle, also /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.45, /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.46 and /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.47 must be valid. Examples of concrete url paths:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.8

Note: resource identifiers may be build of multiple other resource identifiers (see ).

Exception: In some situations the resource identifier is not passed as a path segment but via the authorization information, e.g. an authorization token or session cookie. Here, it is reasonable to use /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.36 as pseudo-identifier path segment. For instance, you may define /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.49 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.50 as resource paths —  and may additionally define endpoints that support identifier passing in the resource path, like define /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.51 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.52.

If a resource is best identified by a compound key consisting of multiple other resource identifiers, it is allowed to reuse the compound key in its natural form containing slashes instead of technical resource identifier in the resource path without violating the above rule as follows:

/info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.9

Example paths:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>0

Note: Exposing a compound key as described above limits ability to evolve the structure of the resource identifier as it is no longer opaque.

To compensate for this drawback, APIs must apply a compound key abstraction consistently in all requests and responses parameters and attributes allowing consumers to treat these as technical resource identifier replacement. The use of independent compound key components must be limited to search and creation requests, as follows:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>1

Where /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.53 is representing the opaque provision of the compound key /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.54 as technical resource identifier.

Remark: A compound key component may itself be used as another resource identifier providing another resource endpoint, e.g /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.55.

If a sub-resource is only accessible via its parent resource and may not exist without parent resource, consider using a nested URL structure, for instance:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>2

However, if the resource can be accessed directly via its unique id, then the API should expose it as a top-level resource. For example, customer has a collection for sales orders; however, sales orders have globally unique id and some services may choose to access the orders directly, for instance:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>3

To keep maintenance and service evolution manageable, we should follow "functional segmentation" and "separation of concern" design principles and do not mix different business functionalities in same API definition. In practice this means that the number of resource types exposed via an API should be limited. In this context a resource type is defined as a set of highly related resources such as a collection, its members and any direct sub-resources.

For example, the resources below would be counted as three resource types, one for customers, one for the addresses, and one for the customers' related addresses:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>4

Note that:

  • We consider /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.56/preferences part of the /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.57 resource type because it has a one-to-one relation to the customer without an additional identifier.

  • We consider /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.57 and /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.56/addresses as separate resource types because /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.56/addresses/{addr} also exists with an additional identifier for the address.

  • We consider /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.61 and /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.56/addresses as separate resource types because there’s no reliable way to be sure they are the same.

Given this definition, our experience is that well defined APIs involve no more than 4 to 8 resource types. There may be exceptions with more complex business domains that require more resources, but you should first check if you can split them into separate subdomains with distinct APIs.

Nevertheless one API should hold all necessary resources to model complete business processes helping clients to understand these flows.

There are main resources (with root url paths) and sub-resources (or nested resources with non-root urls paths). Use sub-resources if their life cycle is (loosely) coupled to the main resource, i.e. the main resource works as collection resource of the subresource entities. You should use ⇐ 3 sub-resource (nesting) levels — more levels increase API complexity and url path length. (Remember, some popular web browsers do not support URLs of more than 2000 characters.)

See also .

If you provide query support for searching, sorting, filtering, and paginating, you must stick to the following naming conventions:

  • : default query parameter, e.g. used by browser tab completion; should have an entity specific alias, e.g. sku.

  • : comma-separated list of fields (as defined by ) to define the sort order. To indicate sorting direction, fields may be prefixed with /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.65 (ascending) or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.39 (descending), e.g. /sales-orders?sort=+id.

  • : field name expression to retrieve only a subset of fields of a resource. See below.

  • : field name expression to expand or embedded sub-entities, e.g. inside of an article entity, expand silhouette code into the silhouette object. Implementing correctly is difficult, so do it with care. See below.

  • : numeric offset of the first element provided on a page representing a collection request. See section below.

  • : an opaque pointer to a page, never to be inspected or constructed by clients. It usually (encrypted) encodes the page position, i.e. the identifier of the first or last page element, the pagination direction, and the applied query filters to recreate the collection. See or section below.

  • : client suggested limit to restrict the number of entries on a page. See section below.

These guidelines provides recommendations for defining JSON data at Zalando. JSON here refers to RFC 7159 (which updates RFC 4627), the "application/json" media type and custom JSON media types defined for APIs. The guidelines clarifies some specific cases to allow Zalando JSON data to have an idiomatic form across teams and services.

Use JSON (RFC 7159) to represent structured (resource) data passed with HTTP requests and responses as body payload. The JSON payload must use a JSON object as top-level data structure (if possible) to allow for future extension. This also applies to collection resources, where you ad-hoc would use an array — see also .

Additionally, the JSON payload must comply to the more restrictive Internet JSON (RFC 7493), particularly

  • on encoding of characters, and

  • on object constraints.

As a consequence, a JSON payload must

  • use

  • consist of , i.e. must not contain non-characters or surrogates, and

  • contain only (no duplicate names).

Non-JSON media types may be supported, if you stick to a business object specific standard format for the payload data, for instance, image data format (JPG, PNG, GIF), document format (PDF, DOC, ODF, PPT), or archive format (TAR, ZIP).

Generic structured data interchange formats other than JSON (e.g. XML, CSV) may be provided, but only additionally to JSON as default format using , for specific use cases where clients may not interpret the payload structure.

You should use standard media types (defined in media type registry of Internet Assigned Numbers Authority (IANA)) as /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.74 (or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.75) header information. More specifically, for JSON payload you should use the standard media type /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.27 (or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.77 for ).

You should avoid using custom media types like /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.78. Custom media types beginning with /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.79 bring no advantage compared to the standard media type for JSON, and make automated processing more difficult.

Exception: Custom media type should be only used in situations where you need to provide (with content negotiation) due to incompatible changes.

Names of arrays should be pluralized to indicate that they contain multiple values. This implies in turn that object names should be singular.

Property names are restricted to ASCII snake_case strings matching regex /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.80. The first character must be a lower case letter, or an underscore, and subsequent characters can be a letter, an underscore, or a number.

Examples:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>5

Rationale: No established industry standard exists, but many popular Internet companies prefer snake_case: e.g. GitHub, Stack Exchange, Twitter. Others, like Google and Amazon, use both - but not only camelCase. It’s essential to establish a consistent look and feel such that JSON looks as if it came from the same hand.

Enumerations should be represented as /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.86 typed OpenAPI definitions of request parameters or model properties. Enum values (using /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.82 or ) need to consistently use the upper-snake case format, e.g. /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.84 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.85. This approach allows to clearly distinguish values from properties or other elements.

Exception: This rule does not apply for case sensitive values sourced from outside API definition scope, e.g. for language codes from ISO 639-1, or when declaring possible values for a [/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.64 parameter].

Dates and date-time properties should end with components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT3 to distinguish them from boolean properties which otherwise would have very similar or even identical names:

  • rather than ,

  • rather than ,

  • /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.93 rather than /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.94, and

  • /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.95 rather than /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.96.

Hint: Use /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.97 (or as /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.98) as required in .

Note: and were mentioned in an earlier version of the guideline and are therefore still accepted for APIs that predate this rule.

A "map" here is a mapping from string keys to some other type. In JSON this is represented as an object, the key-value pairs being represented by property names and property values. In OpenAPI schema (as well as in JSON schema) they should be represented using additionalProperties with a schema defining the value type. Such an object should normally have no other defined properties.

The map keys don’t count as property names in the sense of , and can follow whatever format is natural for their domain. Please document this in the description of the map object’s schema.

Here is an example for such a map definition (the openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>02 property):

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>6

An actual JSON object described by this might then look like this:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>7

OpenAPI 3.x allows to mark properties as openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>04 and as openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>05 to specify whether properties may be absent (openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>06) or components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT5 (openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>08). If a property is defined to be not openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>04 and openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>05 (see ), 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:

requirednullable{}{"example":null}

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11

No

Yes

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>13

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11

Yes

Yes

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>13

No

No

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>13

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>13

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 openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>19. The difference between undecided and decided against any of the options could be modeled as absent and components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT5 respectively. It would be safer to express the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT5 case with a dedicated Null object, e.g. openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>06 compared to openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>23.

Moreover, many major libraries have somewhere between little to no support for a components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT5/absent pattern (see Gson, , Jackson, JSON-B). Especially strongly-typed languages suffer from this since a new composite type is required to express the third state. Nullable openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>25/openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>26/openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>27 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 components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT5 to explicitly indicate property deletion while absent properties are ignored, i.e. not modified.

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, we strongly prefer to replace the boolean with enumeration of named values or statuses - for example accepted_terms_and_conditions with enumeration values YES, NO, UNDEFINED.

Empty array values can unambiguously be represented as the empty list, openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>31.

You must use common field names and semantics whenever applicable. Common fields are idiomatic, create consistency across APIs and support common understanding for API consumers.

We define the following common field names:

  • : the identity of the object. If used, IDs must be opaque strings and not numbers. IDs are unique within some documented context, are stable and don’t change for a given object once assigned, and are never recycled cross entities.

  • : an attribute within one object holding the identifier of another object must use a name that corresponds to the type of the referenced object or the relationship to the referenced object followed by openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>34 (e.g. openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>35 not openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>36, or openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>37 for the reference to a parent node from a child node, even if both have the type openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>38). Exception: We use openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>39 instead of openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>40 for customer facing identification of customers due to legacy reasons. (Hint: openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>40 used to be defined as internal only, technical integer key, see Naming Decision: openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>39 vs openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>40 [internal_link]).

  • : the of an . It typically is used to carry the for subsequent / calls (see and ).

Further common fields are defined in . The following guidelines define standard objects and fields:

Example JSON schema:

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>8

Address structures play a role in different business and use-case contexts, including country variances. All attributes that relate to address information must follow the naming and semantics defined below.

openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>9

Grouping and cardinality of fields in specific data types may vary based on the specific use case (e.g. combining addressee and address fields into a single type when modeling an address label vs distinct addressee and address types when modeling users and their addresses).

Use the following common money structure:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.0

APIs are encouraged to include a reference to the global schema for Money.

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.1

Please note that APIs have to treat Money as a closed data type, i.e. it’s not meant to be used in an inheritance hierarchy. That means the following usage is not allowed:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.2

  • Violates the Liskov Substitution Principle

  • Breaks existing library support, e.g. Jackson Datatype Money

  • Less flexible since both amounts are coupled together, e.g. mixed currencies are impossible

A better approach is to favor composition over inheritance:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.3

  • No inheritance, hence no issue with the substitution principle

  • Makes use of existing library support

  • No coupling, i.e. mixed currencies is an option

  • Prices are now self-describing, atomic values

Please be aware that some business cases (e.g. transactions in Bitcoin) call for a higher precision, so applications must be prepared to accept values with unlimited precision, unless explicitly stated otherwise in the API specification.

Examples for correct representations (in EUR):

  • openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>52 or openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>53 = 42 Euros, 20 Cent

  • openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>54 = 23 Cent

  • openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>55 or openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>56 = 42 Euros

  • openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>57 = 1024 Euros, 42 Cent

  • openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>58 = 1024 Euros, 42.25 Cent

Make sure that you don’t convert the "amount" field to /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.76 / /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.80 types when implementing this interface in a specific language or when doing calculations. Otherwise, you might lose precision. Instead, use exact formats like Java’s openapi: 3.0.1 info: x-api-id: d0184f38-b98d-11e7-9c56-68f728c1ba70 title: Parcel Service API description: API for <...> version: 1.5.8 <...>96. See Stack Overflow for more info.

Some JSON parsers (NodeJS’s, for example) convert numbers to floats by default. After discussing the pros and cons we’ve decided on "decimal" as our amount format. It is not a standard OpenAPI format, but should help us to avoid parsing numbers as float / doubles.

Be compliant with the standardized HTTP method semantics (see HTTP/1 RFC-7230 and RFC-7230 updates from 2014) summarized as follows:

requests are used to read either a single or a collection resource.

  • requests for individual resources will usually generate a if the resource does not exist

  • requests for collection resources may return either (if the collection is empty) or (if the collection is missing)

  • requests must NOT have a request body payload (see )

Note: requests on collection resources should provide sufficient and mechanisms.

APIs sometimes face the problem, that they have to provide extensive structured request information with , 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 must be ignored on server side), API designers have to check the following two options:

  1. 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. with body payload content: when a with URL encoded query parameters is not possible, a request with body payload must be used, and explicitly documented with a hint like in the following example:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.4

Note: It is no option to encode the lengthy structured request information using header parameters. From a conceptual point of view, the semantic of an operation should always be expressed by the resource names, as well as the involved path and query parameters. In other words by everything that goes into the URL. Request headers are reserved for general context information (see ). In addition, size limits on query parameters and headers are not reliable and depend on clients, gateways, server, and actual settings. Thus, switching to headers does not solve the original problem.

Hint: As is used to transport extensive query parameters, the cannot any longer be used to encode the query filters in case of . As a consequence, it is best practice to transport the query filters in the body payload, while using containing the that is only encoding the page position and direction. To protect the pagination sequence the may contain a hash over all applied query filters (See also ).

requests are used to update (and sometimes to create) entire resources – single or collection resources. The semantic is best described as "please put the enclosed representation at the resource mentioned by the URL, replacing any existing resource.".

  • requests are usually applied to single resources, and not to collection resources, as this would imply replacing the entire collection

  • requests are usually robust against non-existence of resources by implicitly creating the resource before updating

  • on successful 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 /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.91)

  • successful requests return or (if the resource was updated - with or without returning the resource), (if the resource was created) or (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 openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>84. You may also support client side steering (see ).

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 for creation of (at least top-level) resources, and focus 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 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 ) without data duplication in case of repetition.

Hint: To prevent unnoticed concurrent updates and duplicate creations when using , you to allow the server to react on stricter demands that expose conflicts and prevent lost updates. See also for details and options.

requests are idiomatically used to create single resources on a 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 request, the server will create one or multiple new resources and provide their URI/URLs in the response

  • successful requests return or (if the resource was updated - with or without returning the resource), (if the resource was created) or (if accepted and processed asynchronously).

Note: By using 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, 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 is used as a workaround (see e.g. ).

Hint: Posting the same resource twice is not required to be (check ) and may result in multiple resources. However, you to prevent this.

method extends HTTP via RFC-5789 standard to update parts of the resource objects where e.g. in contrast to 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 and must be described in the API specification by using specific media types.

  • requests are usually applied to single resources as patching entire collection is challenging

  • requests are usually not robust against non-existence of resource instances

  • on successful requests, the server will update parts of the resource addressed by the URL as defined by the change request in the payload

  • successful requests return or (if the resource was updated - with or without returning the resource).

Note: since implementing correctly is a bit tricky, we strongly suggest to choose one and only one of the following patterns per endpoint (unless forced by a ). In preference order:

  1. use with complete objects to update a resource as long as feasible (i.e. do not use at all).

  2. use with JSON Merge Patch standard, a specialized media type <functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component12 for partial resource representation to update parts of resource objects.

  3. use with JSON Patch standard, a specialized media type <functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component14 that includes instructions on how to change the resource.

  4. use (with a proper description of what is happening) instead of , if the request does not modify the resource in a way defined by the semantics of the standard media types above.

In practice 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 JSON Patch is more powerful while still showing readable patch requests (see also 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.

Note: Patching the same resource twice is not required to be (check ) and may result in a changing result. However, you to prevent this.

Hint: To prevent unnoticed concurrent updates when using you to allow the server to react on stricter demands that expose conflicts and prevent lost updates. See and for details and options.

requests are used to delete resources. The semantic is best described as "please delete the resource identified by the URL".

  • requests are usually applied to single resources, not on collection resources, as this would imply deleting the entire collection.

  • request can be applied to multiple resources at once using query parameters on the collection resource (see ).

  • successful requests return or (if the resource was deleted - with or without returning the resource).

  • failed requests will usually generate (if the resource cannot be found) or (if the resource was already deleted before).

Important: After deleting a resource with , a request on the resource is expected to either return (not found) or (gone) depending on how the resource is represented after deletion. Under no circumstances the resource must be accessible after this operation on its endpoint.

request can have query parameters. Query parameters should be used as filter parameters on a resource and not for passing context information to control the operation behavior.

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.5

Note: When providing with query parameters, API designers must carefully document the behavior in case of (partial) failures to manage client expectations properly.

The response status code of with query parameters requests should be similar to usual requests. In addition, it may return the status code using a payload describing the operation results (see for details).

In rare cases may require additional information, that cannot be classified as filter parameters and thus should be transported via request body payload, to perform the operation. Since states, that has an undefined semantic for payloads, we recommend to utilize . In this case the POST endpoint must be documented with the hint analog to how it is defined for . The response status code of requests should be similar to usual requests.

requests are used to retrieve the header information of single resources and resource collections.

  • has exactly the same semantics as , but returns headers only, no body.

Hint: is particular useful to efficiently lookup whether large resources or collection resources have been updated in conjunction with the -header.

requests are used to inspect the available operations (HTTP methods) of a given endpoint.

  • responses usually either return a comma separated list of methods in the <functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component50 header or as a structured list of link templates

Note: is rarely implemented, though it could be used to self-describe the full functionality of a resource.

Request methods in RESTful services can be…​

  • - the operation semantic is defined to be read-only, meaning it must not have intended side effects, i.e. changes, to the server state.

  • - 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.

  • - 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.

Note: The above definitions, of intended (side) effect allows the server to provide additional state changing behavior as logging, accounting, pre- fetching, etc. However, these actual effects and state changes, must not be intended by the operation so that it can be held accountable.

Method implementations must fulfill the following basic properties according to RFC 7231:

MethodSafeIdempotentCacheable

Yes

Yes

Yes

Yes

Yes

Yes

No

⚠️ No, but

⚠️ May, but only if specific endpoint is . Hint: not supported by most caches.

No

Yes

No

No

⚠️ No, but

No

No

Yes

No

Yes

Yes

No

Yes

Yes

No

Note: .

In many cases it is helpful or even necessary to design and for clients to expose conflicts and prevent resource duplicate (a.k.a. zombie resources) or lost updates, e.g. if same resources may be created or changed in parallel or multiple times. To design an API endpoint owners should consider to apply one of the following three patterns.

  • A resource specific conditional key provided via in the request. The key is in general a meta information of the resource, e.g. a hash or version number, often stored with it. It allows to detect concurrent creations and updates to ensure behavior (see ).

  • A resource specific secondary key provided as resource property in the request body. The secondary key is stored permanently in the resource. It allows to ensure behavior by looking up the unique secondary key in case of multiple independent resource creations from different clients (see ).

  • A client specific idempotency key provided via header in the request. The key is not part of the resource but stored temporarily pointing to the original response to ensure behavior when retrying a request (see ).

Note: While conditional key and secondary key are focused on handling concurrent requests, the idempotency key is focused on providing the exact same responses, which is even a stronger requirement than the . It can be combined with the two other patterns.

To decide, which pattern is suitable for your use case, please consult the following table showing the major properties of each pattern:

Conditional KeySecondary KeyIdempotency Key

Applicable with

/

HTTP Standard

Yes

No

No

Prevents duplicate (zombie) resources

Yes

Yes

No

Prevents concurrent lost updates

Yes

No

No

Supports safe retries

Yes

Yes

Yes

Supports exact same response

No

No

Yes

Can be inspected (by intermediaries)

Yes

No

Yes

Usable without previous

No

Yes

Yes

Note: The patterns applicable to can be applied in the same way to and providing the same properties.

If you mainly aim to support safe retries, we suggest to apply and pattern before the pattern.

Note, like for , successful or returns or (if the resource was updated - with or without returning the resource), or (if resource was created). Hence, clients can differentiate successful robust repetition from resource created server activity of idempotent .

The most important pattern to design for creation is to introduce a resource specific secondary key provided in the request body, to eliminate the problem of duplicate (a.k.a zombie) resources.

The secondary key is stored permanently in the resource as alternate key or combined key (if consisting of multiple properties) guarded by a uniqueness constraint enforced server-side, that is visible when reading the resource. The best and often naturally existing candidate is a unique foreign key, that points to another resource having one-on-one relationship with the newly created resource, e.g. a parent process identifier.

A good example here for a secondary key is the shopping cart ID in an order resource.

Note: When using the secondary key pattern without all subsequent retries should fail with status code (conflict). We suggest to avoid here unless you make sure, that the delivered resource is the original one implementing a well defined behavior. Using without content would be a similar well defined option.

Header and query parameters allow to provide a collection of values, either by providing a comma-separated list of values or by repeating the parameter multiple times with different values as follows:

Parameter TypeComma-separated ValuesMultiple ParametersStandard

Header

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component94

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component95

Query

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component96

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component97

As OpenAPI does not support both schemas at once, an API specification must explicitly define the collection format to guide consumers as follows:

Parameter TypeComma-separated ValuesMultiple Parameters

Header

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component98

not allowed (see )

Query

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component99

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com00

When choosing the collection format, take into account the tool support, the escaping of special characters and the maximal URL length.

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 excellent implementation support in HTTP clients and web frameworks.

Query parameters should have the following aspects specified:

  • Reference to corresponding property, if any

  • Value range, e.g. inclusive vs. exclusive

  • Comparison semantics (equals, less than, greater than, etc)

  • Implications when combined with other queries, e.g. and vs. or

How query parameters are named and used is up to individual API designers. The following examples should serve as ideas:

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com01, to query for elements based on property equality

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com02, to query for elements based on logical properties

    • Assuming that elements don’t actually have an <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com03 but rather a <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com04

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com05, based on upper and lower bounds (<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com06 and <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com07)

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com08, using terminology specific e.g. to length

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com09 or <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com10

    • Using terminology specific e.g. to time: before, after, since and until

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.

Minimalistic query languages based on are suitable for simple use cases with a small set of available filters that are combined in one way and one way only (e.g. and semantics). Simple query languages are generally preferred over complex ones.

Some APIs will have a need for sophisticated and more complex query languages. Dominant examples are APIs around search (incl. faceting) and product catalogs.

Aspects that set those APIs apart from the rest include but are not limited to:

  • Unusual high number of available filters

  • Dynamic filters, due to a dynamic and extensible resource model

  • Free choice of operators, e.g. <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com11, <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com12 and <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com13

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

    • No special library support necessary

    • No need for string concatenation or manual escaping

  • Data structures are easy to use for servers

    • No special tokenizers needed

    • Semantics are attached to data structures rather than text tokens

  • Consistent with other HTTP methods

  • API is defined in OpenAPI completely

    • No external documents or grammars needed

    • Existing means are familiar to everyone

and most certainly needs to make use of the pattern.

The following JSON document should serve as an idea how a structured query might look like.

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.6

Feel free to also get some inspiration from:

  • Elastic Search: Query DSL

  • GraphQL: Queries

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.

Implicit filtering could be done on:

  • the collection of resources being returned on a request

  • 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 when implicit filtering is provided. Example:

If an employee of the company Foo accesses one of our business-to-business service and performs a /business-partners, it must, for legal reasons, not display any other business partner that is not owned or contractually managed by her/his company. It should never see that we are doing business also with company Bar.

Response as seen from a consumer working at <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com17:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.7

Response as seen from a consumer working at <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com18:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.8

The API Specification should then specify something like this:

/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.9

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 IANA Status Code Registry. Main RFC standards are (or ) and RFC 6585 - Additional Status Codes (and there are upcoming new ones, e.g. draft legally-restricted-status). An overview on the official error codes provides Wikipedia: HTTP status codes (which also lists some unofficial status codes, e.g. defined by popular web servers like Nginx, that we do not suggest to use).

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.

API designers should also think about a troubleshooting board as part of the associated online API documentation. It provides information and handling 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.

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>0

The most commonly used codes are best understood and listed below as subset of the official HTTP status codes and consistent with their semantics in the RFCs. We avoid less commonly used codes that easily create misconceptions due to less familiar semantics and API specific interpretations.

Important: As long as your HTTP status code usage is well covered by the semantic defined here, you should not describe it to avoid an overload with common sense information and the risk of inconsistent definitions. Only if the HTTP status code is not in the list below or its usage requires additional information aside the well defined semantic, the API specification must provide a clear description of the HTTP status code in the response.

CodeMeaningMethods

OK - this is the most general success response and used, if the more specific codes below are not applicable.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Created - Returned on successful resource creation. is returned with or without response payload (unlike / ). We recommend to additionally return the created resource URL via the security: - BearerAuth: [ api-repository.read ]2 response header (see ).

,

Accepted - The request was successful and will be processed asynchronously.

, , ,

No content - Returned instead of , if no response payload is returned.

, ,

Multi-Status - The response body contains status information for multiple different parts of a batch/bulk request (see ).

, ()

CodeMeaningMethods

Moved Permanently - This and all future requests should be directed to the given URI.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

See Other - The response to the request can be found under another URI using a method.

, , ,

Not Modified - 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.

,

CodeMeaningMethods

Bad request - unspecific client error indicating that the server cannot process the request 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 status code 422).

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Unauthorized - actually "Unauthenticated": credentials are not valid for the target resource. User must log in.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Forbidden - the user is not authorized to use this resource.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Not found - the resource is not found.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Method Not Allowed - the method is not supported, see .

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Not Acceptable - resource can only generate content not acceptable according to the Accept headers sent in the request.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Request timeout - the server times out waiting for the resource.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Conflict - request cannot be completed due to conflict with the current state of the target resource. For example, you may get a response when updating a resource that is older than the existing one on the server, resulting in a version control conflict. Hint, you should not return , but or in case of successful robust creation of resources (via or ), if the resource already exists.

, , ,

Gone - resource does not exist any longer, e.g. when accessing a resource that has intentionally been deleted.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Precondition Failed - returned for conditional requests, e.g. if the condition failed. Used for optimistic locking.

, ,

Unsupported Media Type - e.g. clients sends request body without content type.

, , ,

Locked - Pessimistic locking, e.g. processing states.

, ,

Precondition Required - server requires the request to be conditional, e.g. to make sure that the "lost update problem" is avoided (see ).

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Too many requests - the client does not consider rate limiting and sent too many requests (see ).

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

CodeMeaningMethods

Internal Server Error - a generic error indication for an unexpected server execution problem (here, client retry may be sensible)

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Not Implemented - server cannot fulfill the request (usually implies future availability, e.g. new feature).

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

Service Unavailable - 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 header.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com19

You must use the most specific HTTP status code when returning information about your request processing status or error situations.

Some APIs are required to provide either batch or bulk requests using for performance reasons, i.e. for communication and processing efficiency. In this case services may be in need to signal multiple response codes for each part of a batch or bulk request. As HTTP does not provide proper guidance for handling batch/bulk requests and responses, we herewith define the following approach:

  • A batch or bulk request always responds with HTTP status code unless a non-item-specific failure occurs.

  • A batch or bulk request may return / status codes, if the failure is non-item-specific and cannot be restricted to individual items of the batch or bulk request, e.g. in case of overload situations or general service failures.

  • A batch or bulk response with status code always returns as payload a multi-status response containing item specific status and/or monitoring information for each part of the batch or bulk request.

Note: These rules apply even in the case that processing of all individual parts fail or each part is executed asynchronously!

The rules are intended to allow clients to act on batch and bulk responses in a consistent way by inspecting the individual results. We explicitly reject the option to apply for a completely successful batch as proposed in Nakadi’s as short cut without inspecting the result, as we want to avoid risks and expect clients to handle partial batch failures anyway.

The bulk or batch response may look as follows:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>1

Note: while a batch defines a collection of requests triggering independent processes, a bulk defines a collection of independent resources created or updated together in one request. With respect to response processing this distinction normally does not matter.

APIs that wish to manage the request rate of clients must use the (Too Many Requests) response code, if the client exceeded the request rate (see RFC 6585). Such responses must also contain header information providing further details to the client. There are two approaches a service can take for header information:

  • Return a header indicating how long the client ought to wait before making a follow-up request. The Retry-After header can contain a HTTP date value to retry after or the number of seconds to delay. Either is acceptable but APIs should prefer to use a delay in seconds.

  • Return a trio of <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com76 headers. These headers (described below) allow a server to express a service level in the form of a number of allowing requests within a given window of time and when the window is reset.

The <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com76 headers are:

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com78: The maximum number of requests that the client is allowed to make in this window.

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com79: The number of requests allowed in the current window.

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com80: The relative time in seconds when the rate limit window will be reset. Beware that this is different to Github and Twitter’s usage of a header with the same name which is using UTC epoch seconds instead.

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 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 returned on every request and not just on a 429, which implies the service implementing the API is carrying sufficient state to track the number of requests made within a given window for each named entity.

RFC 7807 defines a Problem JSON object using the media type /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.77 to provide an extensible human and machine readable failure information beyond the HTTP response status code to transports the failure kind (<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com82 / <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com83) and the failure cause and location (<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com84 / <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com85). To make best use of this additional failure information, every endpoints must be capable of returning a Problem JSON on client usage errors ( status codes) as well as server side processing errors ( status codes).

Note: Clients must be robust and not rely on a Problem JSON object being returned, since (a) failure responses may be created by infrastructure components not aware of this guideline or (b) service may be unable to comply with this guideline in certain error situations.

Hint: The media type /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.77 is often not implemented as a subset of /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.27 by libraries and services! Thus clients need to include /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.77 in the -Header to trigger delivery of the extended failure information.

The OpenAPI schema definition of the Problem JSON object can be found on GitHub. You can reference it by using:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>2

You may define custom problem types as extensions of the Problem JSON object if your API needs to return specific, additional, and more detailed error information.

Note: Problem <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com82 and <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com91 identifiers in our APIs are not meant to be resolved. RFC 7807 encourages that problem types are URI references that point to human-readable documentation, but we deliberately decided against that, as all important parts of the API must be documented using anyway. In addition, URLs tend to be fragile and not very stable over longer periods because of organizational and documentation changes and descriptions might easily get out of sync.

In order to stay compatible with RFC 7807 we proposed to use usually defined by <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com92 as simplified identifiers in <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com82 and <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com91 fields:

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com95

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com96

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com97

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com98

Hint: The use of is not forbidden but strongly discouraged. If you use absolute URIs, please reference instead.

Stack traces contain implementation details that are not part of an API, and on which clients should never rely. Moreover, stack traces can leak sensitive information that partners and third parties are not allowed to receive and may disclose insights about vulnerabilities to attackers.

We describe a handful of standard HTTP headers, which we found raising the most questions in our daily usage, or which are useful in particular circumstances but not widely known.

Though we generally discourage usage of proprietary headers, they are useful to pass generic, service independent, overarching information relevant for our specific application architecture. We consistently define these proprietary headers in this section below. Whether services support these concerns or not is optional. Therefore, the OpenAPI API specification is the right place to make this explicitly visible — use the parameter definitions of the resource HTTP methods.

Use this list and explicitly mention its support in your OpenAPI definition.

This convention is followed by (most of) the standard headers e.g. as defined in RFC 2616 and RFC 4229. Examples:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>3

Note, HTTP standard defines headers as case-insensitive (). However, for sake of readability and consistency you should follow the convention when using standard or proprietary headers. Exceptions are common abbreviations like <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com99.

Content or entity headers are headers with a <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier01 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:

  • can indicate that the representation is supposed to be saved as a file, and the proposed file name.

  • indicates compression or encryption algorithms applied to the content.

  • indicates the length of the content (in bytes).

  • indicates that the body is meant for people literate in some human language(s).

  • indicates where the body can be found otherwise ( for more details]).

  • is used in responses to range requests to indicate which part of the requested resource representation is delivered with the body.

  • indicates the media type of the body content.

As the correct usage of response header (see below) with respect to caching and its method specific semantics is difficult, we discourage the use of . In most cases it is sufficient to inform clients about the resource location in create or re-direct responses by using the header while avoiding the specific ambiguities and complexities.

More details in RFC 7231 ,

is an optional response header that can be used in successful write operations (, , or ) or read operations (, ) 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 and , a different location than the requested URL can be used to indicate that the returned resource is subject to , and that the value provides a more specific identifier of the resource.

  • For writing operations and , an identical location to the requested URL can be used to explicitly indicate that the returned resource is the current representation of the newly created or updated resource.

  • For writing operations and , 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 header, the header has to be set as well. For example:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>4

The security: - BearerAuth: [ api-repository.read ]5 header defined in 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 security: - BearerAuth: [ api-repository.read ]5 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 security: - BearerAuth: [ api-repository.read ]5 header can defined like this in an API definition:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>5

Note: Please copy only the behaviors into your security: - BearerAuth: [ api-repository.read ]5 header specification that are supported by your API endpoint. If necessary, specify different security: - BearerAuth: [ api-repository.read ]5 headers for each supported use case.

Supporting APIs may return the header also defined in RFC 7240 to indicate whether a preference has been applied.

When creating or updating resources it may be necessary to expose conflicts and to prevent the 'lost update' or 'initially created' problem. Following RFC 7232 " Conditional Requests" this can be best accomplished by supporting the header together with the or conditional header. The contents of an <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier44 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 , , or , the <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier48 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 supposed a to respond with status code - precondition failed.

Beside other use cases, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier50 can be used in a similar way to expose conflicts in resource creation. If any matching entity is found, the operation is supposed a to respond with status code - precondition failed.

The , , and headers can be defined as follows in the API definition:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>6

Please see for a detailed discussion and options.

When creating or updating resources it can be helpful or necessary to ensure a strong behavior comprising same responses, to prevent duplicate execution in case of retries after timeout and network outages. Generally, this can be achieved by sending a client specific unique request key – that is not part of the resource – via header.

The unique request key is stored temporarily, e.g. for 24 hours, together with the response and the request hash (optionally) of the first request in a key cache, regardless of whether it succeeded or failed. The service can now look up the unique request key in the key cache and serve the response from the key cache, instead of re-executing the request, to ensure behavior. Optionally, it can check the request hash for consistency before serving the response. If the key is not in the key store, the request is executed as usual and the response is stored in the key cache.

This allows clients to safely retry requests after timeouts, network outages, etc. while receive the same response multiple times. Note: The request retry in this context requires to send the exact same request, i.e. updates of the request that would change the result are off-limits. The request hash in the key cache can protection against this misbehavior. The service is recommended to reject such a request using status code .

Important: To grant a reliable execution semantic, the resource and the key cache have to be updated with hard transaction semantics – considering all potential pitfalls of failures, timeouts, and concurrent requests in a distributed systems. This makes a correct implementation exceeding the local context very hard.

The header must be defined as follows, but you are free to choose your expiration time:

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>7

Hint: The key cache is not intended as request log, and therefore should have a limited lifetime, else it could easily exceed the data resource in size.

Note: The header unlike other headers in this section is not standardized in an RFC. Our only reference are the usage in the Stripe API. However, we do not want to change the header name and semantic, and do not name it like the proprietary headers below. The header addresses a generic REST concern and is different from the Zalando landscape specific proprietary headers.

As a general rule, proprietary HTTP headers should be avoided. From a conceptual point of view, the business semantics and intent of an operation should always be expressed via the URLs path and query parameters, the method, and the content, but not via proprietary headers. Headers are typically used to implement protocol processing aspects, such as flow control, content negotiation, and authentication, and represent business agnostic request modifiers that provide generic context information ().

However, the exceptional usage of proprietary headers is still helpful when domain-specific generic context information…​

  1. needs to be passed end to end along the service call chain (even if not all called services use it as input for steering service behavior e.g. header) and/or…​

  2. is provided by specific gateway components, for instance, our Fashion Shop API or Merchant API gateway.

Below, we explicitly define the list of proprietary header exceptions usable for all services for passing through generic context information of our fashion domain (use case 1).

Per convention, non standardized, proprietary header names are prefixed with <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier59 and use the dash (/info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.39) as separator (dash-case). (Due to backward compatibility, we do not follow the Internet Engineering Task Force’s recommendation in RFC 6648 to deprecate usage of <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier59 headers.) Remember that HTTP header field names are not case-sensitive:

Header field nameTypeDescriptionHeader field value example

String

For more information see .

GKY7oDhpSiKY_gAAAABZ_A

String

Identifies the tenant initiated the request to the multi tenant Zalando Platform. The must be set according to the Business Partner ID extracted from the OAuth token when a request from a Business Partner hits the Zalando Platform.

9f8b3ca3-4be5-436c-a847-9cd55460c495

String

Sales channels are owned by retailers and represent a specific consumer segment being addressed with a specific product assortment that is offered via CFA retailer catalogs to consumers (see fashion platform glossary (internal_link)).

52b96501-0f8d-43e7-82aa-8a96fab134d7

String

Consumer facing applications (CFAs) provide business experience to their customers via different frontend application types, for instance, mobile app or browser. Info should be passed-through as generic aspect — there are diverse concerns, e.g. pushing mobiles with specific coupons, that make use of it. Current range is mobile-app, browser, facebook-app, chat-app, email.

mobile-app

String

There are also use cases for steering customer experience (incl. features and content) depending on device type. Via this header info should be passed-through as generic aspect. Current range is smartphone, tablet, desktop, other.

tablet

String

On top of device type above, we even want to differ between device platform, e.g. smartphone Android vs. iOS. Via this header info should be passed-through as generic aspect. Current range is iOS, Android, Windows, Linux, MacOS.

Android

String

It is either the IDFA (Apple Identifier for mobile Advertising) for iOS, or the GAID (Google mobile Advertising Identifier) for Android. It is a unique, customer-resettable identifier provided by mobile device’s operating system to facilitate personalized advertising, and usually passed by mobile apps via http header when calling backend services. Called services should be ready to pass this parameter through when calling other services. It is not sent if the customer disables it in the settings for respective mobile platform.

b89fadce-1f42-46aa-9c83-b7bc49e76e1f

Exception: The only exception to this guideline are the conventional hop-by-hop <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier71 headers which can be used as defined in .

As part of the guidelines we sourced the OpenAPI definition of all proprietary headers; you can simply reference it when defining the API endpoint requests e.g.

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>8

Response headers can be referenced in the API endpoint e.g.

openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>9

Hint: This guideline does not standardize proprietary headers for our specific gateway components (2. use case above). This include, for instance, non pass-through headers <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier72, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier73, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier74, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier75 defined by Fashion Shop API (RKeep), or <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier76, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier77, <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier78 defined by Merchant API gateway. All these proprietary headers are allowlisted in the API Linter (Zally) checking this rule.

All Zalando’s proprietary headers listed above are end-to-end headers [] and must be propagated to the services down the call chain. The header names and values must remain unchanged.

For example, the values of the custom headers like can affect the results of queries by using device type information to influence recommendation results. Besides, the values of the custom headers can influence the results of the queries (e.g. the device type information influences the recommendation results).

Sometimes the value of a proprietary header will be used as part of the entity in a subsequent request. In such cases, the proprietary headers must still be propagated as headers with the subsequent request, despite the duplication of information.

The is a generic parameter to be passed through service APIs and events and written into log files and traces. A consequent usage of the facilitates the tracking of call flows through our system and allows the correlation of service activities initiated by a specific call. This is extremely helpful for operational troubleshooting and log analysis. Main use case of is to track service calls of our SaaS fashion commerce platform and initiated internal processing flows (executed synchronously via APIs or asynchronously via published events).

The must be passed through:

  • RESTful API requests via proprietary header (see )

  • Published events via <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier86 event field (see )

The following formats are allowed:

  • <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier87 (RFC-4122)

  • <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier88 (RFC-4648)

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.88 ()

  • Random unique string restricted to the character set <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier90 maximal of 128 characters.

Note: If a legacy subsystem can only process <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier91 with a specific format or length, it must define this restriction in its API specification, and be generous and remove invalid characters or cut the length to the supported limit.

Hint: In case distributed tracing is supported by OpenTracing (internal_link) you should ensure that created spans are tagged using <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier86 — see How to Connect Log Output with OpenTracing Using Flow-IDs (internal_link) or Best practises (internal_link).

  • Services must support as generic input, i.e.

    • RESTful API endpoints must support header in requests

    • Event listeners must support the metadata <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier95 from events.

    Note: API-Clients must provide when calling a service or producing events. If no is provided in a request or event, the service must create a new .

  • Services must propagate , i.e. use received with API calls or consumed events as…​

    • input for all API called and events published during processing

    • data field written for logging and tracing

Hint: This rule also applies to application internal interfaces and events not published via Nakadi (but e.g. via AWS SQS, Kinesis or service specific DB solutions).

We strive for a good implementation of as it enables us to build resource-oriented APIs that make full use of HTTP verbs and status codes. You can see this expressed by many rules throughout these guidelines, e.g.:

Although this is not HATEOAS, it should not prevent you from designing proper link relationships in your APIs as stated in rules below.

We do not generally recommend to implement . HATEOAS comes with additional API complexity without real value in our SOA context where client and server interact via REST APIs and provide complex business functions as part of our e-commerce SaaS platform.

Our major concerns regarding the promised advantages of HATEOAS (see also RESTistential Crisis over Hypermedia APIs, Why I Hate HATEOAS and others for a detailed discussion):

  • We follow the with APIs explicitly defined outside the code with standard specification language. HATEOAS does not really add value for SOA client engineers in terms of API self-descriptiveness: a client engineer finds necessary links and usage description (depending on resource state) in the API reference definition anyway.

  • Generic HATEOAS clients which need no prior knowledge about APIs and explore API capabilities based on hypermedia information provided, is a theoretical concept that we haven’t seen working in practice and does not fit to our SOA set-up. The OpenAPI description format (and tooling based on OpenAPI) doesn’t provide sufficient support for HATEOAS either.

  • In practice relevant HATEOAS approximations (e.g. following specifications like HAL or JSON API) support API navigation by abstracting from URL endpoint and HTTP method aspects via link types. So, Hypermedia does not prevent clients from required manual changes when domain model changes over time.

  • Hypermedia make sense for humans, less for SOA machine clients. We would expect use cases where it may provide value more likely in the frontend and human facing service domain.

  • Hypermedia does not prevent API clients to implement shortcuts and directly target resources without 'discovering' them.

However, we do not forbid HATEOAS; you could use it, if you checked its limitations and still see clear value for your usage scenario that justifies its additional complexity. If you use HATEOAS please share experience and present your findings in the API Guild (internal_link).

When embedding links to other resources into representations you must use the common hypertext control object. It contains at least one attribute:

  • : The URI of the resource the hypertext control is linking to. All our API are using HTTP(s) as URI scheme.

In API that contain any hypertext controls, the attribute name is reserved for usage within hypertext controls.

The schema for hypertext controls can be derived from this model:

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component0

The name of an attribute holding such a components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT03 object specifies the relation between the object that contains the link and the linked resource. Implementations should use names from the IANA Link Relation Registry whenever appropriate. As IANA link relation names use hyphen-case notation, while this guide enforces snake_case notation for attribute names, hyphens in IANA names have to be replaced with underscores (e.g. the IANA link relation type components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT04 would become the attribute components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT05)

Specific link objects may extend the basic link type with additional attributes, to give additional information related to the linked resource or the relationship between the source resource and the linked one.

E.g. a service providing "Person" resources could model a person who is married with some other person with a hypertext control that contains attributes which describe the other person (openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>32, components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT07) but also the relationship "spouse" between the two persons (components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT08):

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component1

Hypertext controls are allowed anywhere within a JSON model. While this specification would allow HAL, we actually don’t recommend/enforce the usage of HAL anymore as the structural separation of meta-data and data creates more harm than value to the understandability and usability of an API.

For pagination and self-references a simplified form of the should be used to reduce the specification and cognitive overhead. It consists of a simple URI value in combination with the corresponding link relations, e.g. , , , , or .

See and for more information and examples.

Links to other resource must always use full, absolute URI.

Motivation: Exposing any form of relative URI (no matter if the relative URI uses an absolute or relative path) introduces avoidable client side complexity. It also requires clarity on the base URI, which might not be given when using features like embedding subresources. The primary advantage of non-absolute URI is reduction of the payload size, which is better achievable by following the recommendation to use

For flexibility and precision, we prefer links to be directly embedded in the JSON payload instead of being attached using the uncommon link header syntax. As a result, the use of the in conjunction with JSON media types is forbidden.

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:

  • compression of request and response bodies (see )

  • querying field filters to retrieve a subset of resource attributes (see below)

  • and / headers to avoid re-fetching of unchanged resources (see )

  • security: - BearerAuth: [ api-repository.read ]5 header with components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT23 or components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT24 to anticipate reduced processing requirements of clients (see )

  • 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 ).

Each of these items is described in greater detail below.

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 request header — see also . The server should indicate used gzip compression via the header.

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 explicitly determine the subset of fields he wants to receive via the query parameter. (It is analogue to and simple queries, and also applied, for instance, for .)

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component2

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component3

The query parameter determines the fields returned with the response payload object. For instance, components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT35 returns components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT36 root object with only the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT07 field, and components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT38 returns the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT07 and the nested components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT40 object with only its components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT07 field.

OpenAPI doesn’t support you in formally specifying different return object schemes depending on a parameter. When you define the field parameter, we recommend to provide the following description: components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT42

The syntax of the query value is defined by the following BNF grammar.

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component4

Note: Following the principle of least astonishment, you should not define the query parameter using a default value, as the result is counter-intuitive and very likely not anticipated by the consumer.

Embedding related resources (also know as Resource expansion) is a great way to reduce the number of requests. In cases where clients know upfront that they need some related resources they can instruct the server to prefetch that data eagerly. Whether this is optimized on the server, e.g. a database join, or done in a generic way, e.g. an HTTP proxy that transparently embeds resources, is up to the implementation.

See for naming, e.g. "embed" for steering of embedded resource expansion. Please use the BNF grammar, as already defined above for filtering, when it comes to an embedding query syntax.

Embedding a sub-resource can possibly look like this where an order resource has its order items as sub-resource (/order/{orderId}/items):

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component5

Caching has to take many aspects into account, e.g. general of response information, our guideline to protect endpoints using SSL and , resource update and invalidation rules, existence of multiple consumer instances. As a consequence, caching is in best case complex, e.g. with respect to consistency, in worst case inefficient.

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 and consumers should always set the header set to and assume the same setting, if no header is provided.

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.

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component6

If your service really requires to support caching, please observe the following rules:

  • Document all , , and endpoints by declaring the support of , , and headers in response. Note: you must not define the 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 and 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 on all endpoints.

    • For larger data items support requests or more efficient requests with header to check for updates.

    • For small data sets provide full collection requests supporting , as well as requests or requests with to check for updates.

    • For medium sized data sets provide full collection requests supporting together with and filtering requests for limiting the response to changes since the provided . Note: this is not supported by generic client and proxy caches on HTTP layer.

Hint: For proper cache support, you must return without content on a failed or request with instead of .

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component7

Hint: For source see .

The default setting for should contain the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT84 directive for endpoints with standard , as well as the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT85 directive to ensure, that the client does not use stale cache entries. Last, the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT86 directive should be set to a value between a few seconds (components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT87) and a few hours (components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT88) depending on the change rate of your master data and your requirements to keep clients consistent.

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component8

The default setting for 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:

<functional-name> ::= <functional-domain>-<functional-component> <functional-domain> ::= [a-z][a-z0-9-]* -- managed functional group of components <functional-component> ::= [a-z][a-z0-9-]* -- name of API owning functional component9

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 header and greatly simplifies interpreting the and headers. Moreover, is highly efficient with respect to caching performance and overhead, and allows to support more .

Anyhow, please carefully read RFC 7234 before adding any client or proxy cache.

Access to lists of data items must support pagination to protect the service against overload as well as to support client side iteration and batch processing experience. This holds true for all lists that are (potentially) larger than just a few hundred entries.

There are two well known page iteration techniques:

  • Offset-based pagination: numeric offset identifies the first page-entry

  • Cursor-based pagination — aka key-based pagination: a unique key identifies the first page-entry (see also Twitter API or Facebook API)

The technical conception of pagination should also consider user experience (see Pagination Usability Findings In eCommerce), for instance, jumping to a specific page is far less used than navigation via / page links (see ). This favors an API design using cursor-based instead of offset-based pagination — see .

Note: To provide a consistent look and feel of pagination patterns, you must stick to the common query parameter names defined in .

Cursor-based pagination is usually better and more efficient when compared to offset-based pagination. Especially when it comes to high-data volumes and/or storage in NoSQL databases.

Before choosing cursor-based pagination, consider the following trade-offs:

  • Usability/framework support:

    • Offset-based pagination is more widely known than cursor-based pagination, so it has more framework support and is easier to use for API clients

  • Use case - jump to a certain page:

    • If jumping to a particular page in a range (e.g., 51 of 100) is really a required use case, cursor-based navigation is not feasible.

  • Data changes may lead to anomalies in result pages:

    • Offset-based pagination may create duplicates or lead to missing entries if rows are inserted or deleted between two subsequent paging requests.

    • If implemented incorrectly, cursor-based pagination may fail when the cursor entry has been deleted before fetching the pages.

  • Performance considerations - efficient server-side processing using offset-based pagination is hardly feasible for:

    • Very big data sets, especially if they cannot reside in the main memory of the database.

    • Sharded or NoSQL databases.

  • Cursor-based navigation may not work if you need the total count of results.

The used for pagination is an opaque pointer to a page, that must never be inspected or constructed by clients. It usually encodes (encrypts) the page position, i.e. the unique identifier of the first or last page element, the pagination direction, and the applied query filters (or a hash over these) to safely recreate the collection (see also best practice below).

For iterating over collections (result sets) we propose to either use cursors (see ) or simple hypertext control links (see ). To implement these in a consistent way, we have defined a response page object pattern with the following field semantics:

  • :the link or cursor pointing to the same page.

  • : the link or cursor pointing to the first page.

  • : the link or cursor pointing to the previous page. It is not provided, if it is the first page.

  • : the link or cursor pointing to the next page. It is not provided, if it is the last page.

  • : the link or cursor pointing to the last page.

Pagination responses should contain the following additional array field to transport the page content:

  • : array of resources, holding all the items of the current page ( may be replaced by a resource name).

To simplify user experience, the applied query filters may be returned using the following field (see also ):

  • : object containing the query filters applied in the search request to filter the collection resource.

As Result, the standard response page using or may be defined as follows:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com0

Note: While you may support cursors for , , , , and , it is best practice to replace these with pagination links — see .

To simplify client design, APIs should support as standard pagination links where applicable:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com1

See also for details on the pagination fields and page result object.

Remark: You should avoid providing a total count unless there is a clear need to do so. Very often, there are significant system and performance implications when supporting full counts. Especially, if the data set grows and requests become complex queries and filters drive full scans. While this is an implementation detail relative to the API, it is important to consider the ability to support serving counts over the life of a service.

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 with

We strongly encourage using compatible API extensions and discourage versioning (see and below). The following guidelines for service providers () and consumers () 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 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.

API designers should apply the following rules to evolve RESTful APIs for services in a backward-compatible way:

  • Add only optional, never mandatory fields.

  • Never change the semantic of fields (e.g. changing the semantic from customer-number to customer-id, as both are different unique customer keys)

  • Input fields may have (complex) constraints being validated via server-side business logic. Never change the validation logic to be more restrictive and make sure that all constraints are clearly defined in description.

  • Enum ranges can be reduced when used as input parameters, only if the server is ready to accept and handle old range values too. 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. However, enum ranges can be extended when used for input parameters.

  • Use , 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.

  • Support redirection in case an URL has to change (Moved Permanently).

Designers of service provider APIs should be conservative and accurate in what they accept from clients:

  • Unknown input fields in payload or URL should not be ignored; servers should provide error feedback to clients via an HTTP 400 response code.

  • Be accurate in defining input data constraints (like formats, ranges, lengths etc.) — and check constraints and return dedicated error information in case of violations.

  • Prefer being more specific and restrictive (if compliant to functional requirements), e.g. by defining length range of strings. It may simplify implementation while providing freedom for further evolution as compatible extensions.

Not ignoring unknown input fields is a specific deviation from Postel’s Law (e.g. see also
The Robustness Principle Reconsidered) and a strong recommendation. Servers might want to take different approach but should be aware of the following problems and be explicit in what is supported:

  • Ignoring unknown input fields is actually not an option for , since it becomes asymmetric with subsequent response and HTTP is clear about the replace semantics and default roundtrip expectations (see ). Note, accepting (i.e. not ignoring) unknown input fields and returning it in subsequent responses is a different situation and compliant to semantics.

  • Certain client errors cannot be recognized by servers, e.g. attribute name typing errors will be ignored without server error feedback. The server cannot differentiate between the client intentionally providing an additional field versus the client sending a mistakenly named field, when the client’s actual intent was to provide an optional input field.

  • Future extensions of the input data structure might be in conflict with already ignored fields and, hence, will not be compatible, i.e. break clients that already use this field but with different type.

In specific situations, where a (known) input field is not needed anymore, it either can stay in the API definition with "not used anymore" description or can be removed from the API definition as long as the server ignores this specific parameter.

Service clients should apply the robustness principle:

  • Be conservative with API requests and data passed as input, e.g. avoid to exploit definition deficits like passing megabytes of strings with unspecified maximum length.

  • Be tolerant in processing and reading data of API responses, more specifically service clients must be prepared for compatible API extensions of response data:

    • Be tolerant with unknown fields in the payload (see also Fowler’s "TolerantReader" post), i.e. ignore new fields but do not eliminate them from payload if needed for subsequent requests.

    • Be prepared that return parameter may deliver new values; either be agnostic or provide default behavior for unknown values.

    • Be prepared to handle HTTP status codes not explicitly specified in endpoint definitions. Note also, that status codes are extensible. Default handling is how you would treat the corresponding code (see ).

    • Follow the redirect when the server returns HTTP status code (Moved Permanently).

The OpenAPI specification is not very specific on default extensibility of objects, and redefines JSON-Schema keywords related to extensibility, like components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4. Following our compatibility guidelines, OpenAPI object definitions are considered open for extension by default as per of JSON-Schema.

When it comes to OpenAPI, this means an components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 declaration is not required to make an object definition extensible:

  • API clients consuming data must not assume that objects are closed for extension in the absence of an components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 declaration and must ignore fields sent by the server they cannot process. This allows API servers to evolve their data formats.

  • For API servers receiving unexpected data, the situation is slightly different. Instead of ignoring fields, servers may reject requests whose entities contain undefined fields in order to signal to clients that those fields would not be stored on behalf of the client. API designers must document clearly how unexpected fields are handled for , , and requests.

API formats must not declare components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 to be false, as this prevents objects being extended in the future.

Note that this guideline concentrates on default extensibility and does not exclude the use of components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 with a schema as a value, which might be appropriate in some circumstances, e.g. see .

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.

However, when API versioning is unavoidable, you have to design your multi-version RESTful APIs using media type versioning (see ). 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 <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier09 header — e.g. security: - BearerAuth: [ api-repository.read ]28. For incompatible changes, a new media type version for the resource is created. To generate the new representation version, consumer and producer can do using the HTTP <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier09 and /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.24 headers.

Note

This versioning method only applies to the request and response payload schema, not to URI or method semantics.

Custom media type format should have the following pattern:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com2

  • security: - BearerAuth: [ api-repository.read ]31 is a custom type name, e.g. security: - BearerAuth: [ api-repository.read ]32

  • security: - BearerAuth: [ api-repository.read ]33 is a (sequence) number, e.g. security: - BearerAuth: [ api-repository.read ]34

In this example, a client wants only the new version of the response:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com3

A server responding to this, as well as a client sending a request with content should use the <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier09 header, declaring that one is sending the new version:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com4

Media type versioning should…​

  • Use a custom media type, e.g. security: - BearerAuth: [ api-repository.read ]36

  • Include media type versions in request and response headers to increase visibility

  • Include <application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier09 in the components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT55 header to enable proxy caches to differ between versions

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com5

Note

Until an incompatible change is necessary, it is recommended to stay with the standard /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.27 media type without versioning.

Further reading: API Versioning Has No "Right Way" provides an overview on different versioning approaches to handle breaking changes without being opinionated.

With URL versioning a (major) version number is included in the path, e.g. security: - BearerAuth: [ api-repository.read ]40. 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 URL versioning, instead we with content negotiation.

In a response body, you must always return a JSON object (and not e.g. an array) as a top level data structure to support future extensibility. JSON objects support compatible extension by additional attributes. This allows you to easily extend your response and e.g. add pagination later, without breaking backwards compatibility. See for an example.

Maps (see ), even though technically objects, are also forbidden as top level data structures, since they don’t support compatible, future extensions.

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:

  1. 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

  2. the list of values is complete with respect to any thinkable and unthinkable future feature.

To specify an open-ended list of values use the marker as follows:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com6

Note: is not JSON Schema conform but will be ignored by most tools.

See about enum value naming conventions.

Important: Clients must be prepared for extensions of enums returned with server responses, i.e. must implement a fallback / default behavior to handle unknown new enum values — see . API owners must take care to extend enums in a compatible way that does not change the semantics of already existing enum values, for instance, do not split an old enum value into two new enum values.

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.

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 security: - BearerAuth: [ api-repository.read ]45 for the affected element and add further explanation to the security: - BearerAuth: [ api-repository.read ]46 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.

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 ). Once all clients of a sunset API feature are migrated, the producer may shut down the deprecated API feature.

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.

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 .

During the deprecation phase, the producer should add a security: - BearerAuth: [ api-repository.read ]51 (see draft: RFC Deprecation HTTP Header) and - if also planned - a security: - BearerAuth: [ api-repository.read ]52 (see ) header on each response affected by a deprecated element (see ).

The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.06 header can either be set to openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11 - 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 ). The optional /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.07 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.

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com7

If multiple elements are deprecated the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.06 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.07 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 /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.06 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.07 header is not sufficient to gain client consent to shut down an API or feature.

Hint: In earlier guideline versions, we used the security: - BearerAuth: [ api-repository.read ]60 header to provide the deprecation info to clients. However, security: - BearerAuth: [ api-repository.read ]60 header has a less specific semantics, will be obsolete with draft: RFC HTTP Caching, and our syntax was not compliant with .

Clients should monitor the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.06 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.07 headers in HTTP responses to get information about future sunset of APIs and API features (see ). 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 security: - BearerAuth: [ api-repository.read ]60 header to provide the deprecation info (see hint in ).

Clients must not start using deprecated APIs, API versions, or API features.

All service applications must publish OpenAPI specifications of their external APIs. While this is optional for internal APIs, i.e. APIs marked with the component-internal group, we still recommend to do so to profit from the API management infrastructure.

An API is published by copying its OpenAPI specification into the reserved /zalando-apis directory of the deployment artifact used to deploy the provisioning service. The directory must only contain self-contained YAML files that each describe one API (exception see ). We prefer this deployment artifact-based method over the past (now legacy) security: - BearerAuth: [ api-repository.read ]71 service endpoint-based publishing process, that we only support for backward compatibility reasons.

Background: In our dynamic and complex service infrastructure, it is important to provide API client developers a central place with online access to the API specifications of all running applications. As a part of the infrastructure, the API publishing process is used to detect API specifications. The findings are published in the API Portal - the universal hub for all Zalando APIs.

Note: To publish an API, it is still necessary to deploy the artifact successful, as we focus the discovery experience on APIs supported by running services.

Owners of APIs used in production should monitor API service to get information about its using clients. This information, for instance, is useful to identify potential review partner for API changes.

Hint: A preferred way of client detection implementation is by logging of the client-id retrieved from the OAuth token.

Zalando’s architecture centers around decoupled microservices and in that context we favour asynchronous event driven approaches. The guidelines focus on how to design and publish events intended to be shared for others to consume.

Events are defined using an item called an Event Type. The Event Type allows events to have their structure declared with a schema by producers and understood by consumers. An Event Type declares standard information, such as a name, an owning application (and by implication, an owning team), a schema defining the event’s custom data, and a compatibility mode declaring how the schema will be evolved. Event Types also allow the declaration of validation and enrichment strategies for events, along with supplemental information such as how events can be partitioned in an event stream.

Event Types belong to a well known Event Category (such as a data change category), which provides extra information that is common to that kind of event.

Event Types can be published and made available as API resources for teams to use, typically in an Event Type Registry. Each event published can then be validated against the overall structure of its event type and the schema for its custom data.

The basic model described above was originally developed in the Nakadi project, which acts as a reference implementation (see also Nakadi API (internal_link)) of the event type registry, and as a validating publish/subscribe broker for event producers and consumers.

Events must be consistent with other API data and the API Guidelines in general (as far as applicable).

Everything expressed in the to these Guidelines is applicable to event data interchange between services. This is because our events, just like our APIs, represent a commitment to express what our systems do and designing high-quality, useful events allows us to develop new and interesting products and services.

What distinguishes events from other kinds of data is the delivery style used, asynchronous publish-subscribe messaging. But there is no reason why they could not be made available using a REST API, for example via a search request or as a paginated feed, and it will be common to base events on the models created for the service’s REST API.

The following existing guideline sections are applicable to events:

Events are part of a service’s interface to the outside world equivalent in standing to a service’s REST API. Services publishing data for integration must treat their events as a first class design concern, just as they would an API. For example this means approaching events with the "API first" principle in mind as described in the .

Services publishing event data for use by others must make the event schema as well as the event type definition available for review.

In Zalando’s architecture, events are registered using a structure called an Event Type. The Event Type declares standard information as follows:

  • A well known event category, such as a general or data change category.

  • The name of the event type.

  • The definition of the .

  • An owning application, and by implication, an owning team.

  • A schema defining the event payload.

  • The compatibility mode for the type.

Event Types allow easier discovery of event information and ensure that information is well-structured, consistent, and can be validated. The core Event Type structure is shown below as an OpenAPI object definition:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com8

APIs such as registries supporting event types, may extend the model, including the set of supported categories and schema formats. For example the Nakadi API’s event category registration also allows the declaration of validation and enrichment strategies for events, along with supplemental information, such as how events are partitioned in the stream (see ).

Event type names must (or should, see for details and definition) conform to the functional naming depending on the as follows:

<hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com9

Hint: The following convention (e.g. used by legacy STUPS infrastructure) is deprecated and only allowed for event type names:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier0

Note: consistent naming should be used whenever the same entity is exposed by a data change event and a RESTful API.

Event definitions must have clear ownership - this can be indicated via the security: - BearerAuth: [ api-repository.read ]72 field of the EventType.

Typically there is one producer application, which owns the EventType and is responsible for its definition, akin to how RESTful API definitions are managed. However, the owner may also be a particular service from a set of multiple services that are producing the same kind of event.

Event type owners must pay attention to the choice of compatibility mode. The mode provides a means to evolve the schema. The range of modes are designed to be flexible enough so that producers can evolve schemas while not inadvertently breaking existing consumers:

  • security: - BearerAuth: [ api-repository.read ]73: Any schema modification is accepted, even if it might break existing producers or consumers. When validating events, undefined properties are accepted unless declared in the schema.

  • security: - BearerAuth: [ api-repository.read ]74: A schema security: - BearerAuth: [ api-repository.read ]75 is forward compatible if the previously registered schema, security: - BearerAuth: [ api-repository.read ]76 can read events defined by security: - BearerAuth: [ api-repository.read ]75 - that is, consumers can read events tagged with the latest schema version using the previous version as long as consumers follow the robustness principle described in the guideline’s .

  • security: - BearerAuth: [ api-repository.read ]78: This means changes are fully compatible. A new schema, security: - BearerAuth: [ api-repository.read ]75, is fully compatible when every event published since the first schema version will validate against the latest schema. In compatible mode, only the addition of new optional properties and definitions to an existing schema is allowed. Other changes are forbidden.

To align the event schema specifications to API specifications, we use the Schema Object as defined by the OpenAPI Specifications to define event schemas. This is particularly useful for events that represent data changes about resources also used in other APIs.

The is an extended subset of JSON Schema Draft 4. For convenience, we highlight some important differences below. Please refer to the for details.

As the OpenAPI Schema Object specification removes some JSON Schema keywords, the following properties must not be used in event schemas:

  • security: - BearerAuth: [ api-repository.read ]80

  • security: - BearerAuth: [ api-repository.read ]81

  • security: - BearerAuth: [ api-repository.read ]82

  • security: - BearerAuth: [ api-repository.read ]83

  • security: - BearerAuth: [ api-repository.read ]84

  • security: - BearerAuth: [ api-repository.read ]85

  • <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com13

  • security: - BearerAuth: [ api-repository.read ]87

On the other side Schema Object redefines some JSON Schema keywords:

  • components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4: For event types that declare compatibility guarantees, there are recommended constraints around the use of this field. See the guideline for details.

Finally, the Schema Object extends JSON Schema with some keywords:

  • security: - BearerAuth: [ api-repository.read ]90: events are logically immutable, so security: - BearerAuth: [ api-repository.read ]90 can be considered redundant, but harmless.

  • security: - BearerAuth: [ api-repository.read ]92: to support polymorphism, as an alternative to security: - BearerAuth: [ api-repository.read ]87.

  • security: - BearerAuth: [ api-repository.read ]94: patterned objects in the form of can be used in event type schema, but it might be the case that general purpose validators do not understand them to enforce a validation check, and fall back to must-ignore processing. A future version of the guidelines may define well known vendor extensions for events.

Event type schema should avoid using components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 declarations, in order to support schema evolution.

Events are often intermediated by publish/subscribe systems and are commonly captured in logs or long term storage to be read later. In particular, the schemas used by publishers and consumers can
drift over time. As a result, compatibility and extensibility issues that happen less frequently with client-server style APIs become important and regular considerations for event design. The guidelines recommend the following to enable event schema evolution:

  • Publishers who intend to provide compatibility and allow their schemas to evolve safely over time must not declare an components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 field with a value of openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>11 (i.e., a wildcard extension point). Instead they must define new optional fields and update their schemas in advance of publishing those fields.

  • Consumers must ignore fields they cannot process and not raise errors. This can happen if they are processing events with an older copy of the event schema than the one containing the new definitions specified by the publishers.

The above constraint does not mean fields can never be added in future revisions of an event type schema - additive compatible changes are allowed, only that the new schema for an event type must define the field first before it is published within an event. By the same turn the consumer must ignore fields it does not know about from its copy of the schema, just as they would as an API client - that is, they cannot treat the absence of an components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4 field as though the event type schema was closed for extension.

Requiring event publishers to define their fields ahead of publishing avoids the problem of field redefinition. This is when a publisher defines a field to be of a different type that was already being emitted, or, is changing the type of an undefined field. Both of these are prevented by not using components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4.

See also rule in the section for further guidelines on the use of components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT4.

Event schemas must be versioned — analog to for REST API definitions. The compatibility mode interact with revision numbers in the schema /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.002 field, which follows semantic versioning (MAJOR.MINOR.PATCH):

  • Changing an event type with compatibility mode security: - BearerAuth: [ api-repository.read ]78 or security: - BearerAuth: [ api-repository.read ]74 can lead to a PATCH or MINOR version revision. MAJOR breaking changes are not allowed.

  • Changing an event type with compatibility mode security: - BearerAuth: [ api-repository.read ]73 can lead to PATCH, MINOR or MAJOR level changes.

The following examples illustrate these relations:

  • Changes to the event type’s <hostname> ::= <functional-hostname> | <application-hostname> <functional-hostname> ::= <functional-name>.zalandoapis.com83 or security: - BearerAuth: [ api-repository.read ]46 are considered PATCH level.

  • Adding new optional fields to an event type’s schema is considered a MINOR level change.

  • All other changes are considered MAJOR level, such as renaming or removing fields, or adding new required fields.

An event category describes a generic class of event types. The guidelines define two such categories:

  • General Event: a general purpose category.

  • Data Change Event: a category to inform about data entity changes and used e.g. for data replication based data integration.

A category describes a predefined structure (e.g. including event metadata as part of the event payload) that event publishers must conform to along with standard information specific for the event category (e.g. the operation for data change events).

The structure of the General Event Category is shown below as an OpenAPI Schema Object definition:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier1

Event types based on the General Event Category define their custom schema payload at the top-level of the document, with the field being reserved for standard information (the contents of are described further down in this section).

Note:

  • The General Event was called a Business Event in earlier versions of the guidelines. Implementation experience has shown that the category’s structure gets used for other kinds of events, hence the name has been generalized to reflect how teams are using it.

  • The General Event is still useful and recommended for the purpose of defining events that drive a business process.

  • The Nakadi broker still refers to the General Category as the Business Category and uses the keyword /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.008 for event type registration. Other than that, the JSON structures are identical.

See for more guidance on how to use the category.

The Data Change Event Category structure is shown below as an OpenAPI Schema Object:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier2

The Data Change Event Category is structurally different to the General Event Category by defining a field called /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.009 as container for the custom payload, as well as specific information related to data changes in the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.010.

The following guidelines specifically apply to Data Change Events:

The General and Data Change event categories share a common structure for metadata representing generic event information. Parts of the metadata is provided by the Nakadi event messaging platform, but event identifier (eid) and event creation timestamp (occurred_at) have to be provided by the event producers. The metadata structure is defined below as an OpenAPI Schema Object:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier3

Please note that intermediaries acting between the producer of an event and its ultimate consumers, may perform operations like validation of events and enrichment of an event’s . For example brokers such as Nakadi, can validate and enrich events with arbitrary additional fields that are not specified here and may set default or other values, if some of the specified fields are not supplied. How such systems work is outside the scope of these guidelines but producers and consumers working with such systems should look into their documentation for additional information.

Event publishers must provide the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 (event identifier) as a standard event object field and part of the event . The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 must be a unique identifier for the event in the scope of the event type / stream lifetime.

Event producers must use the same /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 when publishing the same event object multiple times. For instance, producers must ensure that publish event retries — e.g. due to temporary Nakadi or network failures or fail-overs — use the same /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 value as the initial (possibly failed) attempt.

The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 supports event consumers in detecting and being robust against event duplicates — see .

Hint: Using the same eid for retries can be ensured, for instance, by generating a UUID either (i) as part of the event object construction and using some form of intermediate persistence, like an event publish retry queue, or (ii) via a deterministic function that computes the UUID value from the event fields as input (without random salt).

When publishing events that represent steps in a business process, event types must be based on the General Event category. All your events of a single business process will conform to the following rules:

  • Business events must contain a specific identifier field (a business process id or "bp-id") similar to flow-id to allow for efficient aggregation of all events in a business process execution.

  • Business events must contain a means to correctly order events in a business process execution. In distributed settings where monotonically increasing values (such as a high precision timestamp that is assured to move forwards) cannot be obtained, the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.016 data structure allows causal relationships to be declared between events.

  • Business events should only contain information that is new to the business process execution at the specific step/arrival point.

  • Each business process sequence should be started by a business event containing all relevant context information.

  • Business events must be published reliably by the service.

At the moment we cannot state whether it’s best practice to publish all the events for a business process using a single event type and represent the specific steps with a state field, or whether to use multiple event types to represent each step. For now we suggest assessing each option and sticking to one for a given business process.

Event processing consumer applications need the order information to reconstruct the business event stream, for instance, in order to replay events in error situations, or to execute analytical use cases outside the context of the original event stream consumption. All general events (fka business events) should be provided with the explicit information about the business ordering of the events. To accomplish this event ordering the event type definition

  • must specify a the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.017 property to indicate which field(s) contain the ordering key, and

  • should specify the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.018 property to define which field(s) represents the business entity instance identifier.

Note: The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.018 restrict the scope in which the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.017 provide the strict order. If undefined, the ordering is assumed to be provided in scope of all events.

The business ordering information can be provided – among other ways – by maintaining…​

  • a strictly monotonically increasing version of entity instances (e.g. created as row update counter by a database), or

  • a strictly monotonically increasing sequence counter (maintained per partition or event type).

Hint: timestamps are often a bad choice, since in distributed systems events may occur at the same time, or clocks are not exactly synchronized, or jump forward and backward to compensate drifts or leap-seconds. If you use anyway timestamps to indicate event ordering, you must carefully ensure that the designated event order is not messed up by these effects and use UTC time zone format.

Note: The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.021 and /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.022 metadata set by Nakadi typically is different from the business event ordering, since (1) Nakadi is a distributed concurrent system without atomic, ordered event creation and (2) the application’s implementation of event publishing may not exactly reflect the business order. The business ordering information is application knowledge, and implemented in the scope of event partitions or specific entities, but may also comprise all events, if scaling requirements are low.

You must use data change events to signal changes of stored entity instances and facilitate e.g. change data capture (CDC). Event sourced change data capture is crucial for our data integration architecture as it supports the logical replication (and reconstruction) of the application datastores to the data analytics and AI platform as transactional source datasets.

  • Change events must be provided when publishing events that represent created, updated, or deleted data.

  • Change events must provide the complete entity data including the identifier of the changed instance to allow aggregation of all related events for the entity.

  • Change events .

  • Change events must be published reliably by the service.

While the order information is recommended for business events, it must be provided for data change events. The ordering information defines the (create, update, delete) change order of the data entity instances managed via the application’s transactional datastore. It is needed for change data capture to keep transactional dataset replicas in sync as source for data analytics.

For details about how to provide the data change ordering information, please check .

Exception: In situations where the transactional data is 'append only', i.e. entity instances are only created, but never updated or deleted, the ordering information may not be provided.

The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.023 partition strategy allows a producer to define which fields in an event are used as input to compute a logical partition the event should be added to. Partitions are useful as they allow supporting systems to scale their throughput while provide local ordering for event entities.

The /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.023 option is particularly useful for data changes as it allows all related events for an entity to be consistently assigned to a partition, providing a relative ordered stream of events for that entity. This is because while each partition has a total ordering, ordering across partitions is not assured by a supporting system, thus it is possible for events sent across partitions to appear in a different order to consumers that the order they arrived at the server.

When using the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.023 strategy the partition key in almost all cases should represent the entity being changed and not a per event or change identifier such as the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 field or a timestamp. This ensures data changes arrive at the same partition for a given entity and can be consumed effectively by clients.

There may be exceptional cases where data change events could have their partition strategy set to be the producer defined or random options, but generally /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.023 is the right option - that is while the guidelines here are a "should", they can be read as "must, unless you have a very good reason".

Event data security is supported by Nakadi Event Bus mechanisms for access control and authorization of publishing or consuming events. However, we avoid writing sensitive data (e.g. personal data like e-mail or address) to events unless it is needed for the business. Sensitive data create additional obligations for access control and compliance and generally increases data protection risks.

Duplicate events are multiple occurrences of the same event object representing the same (business or data change) event instance.

Event consumers must be robust against duplicate events. Depending on the use case, being robust implies that event consumers need to deduplicate events, i.e. to ignore duplicates in event processing. For instance, for accounting reporting a high accuracy is required by the business, and duplicates need to be explicitly ignored, whereas customer behavior reporting (click rates) might not care about event duplicates since accuracy in per-mille range is not needed.

Hint: Event consumers are supported in deduplication:

  • Deduplication can be based on the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.011 as mandatory standard for all events — see .

  • Processing data change events to replay data changes and keep transactional data copies in sync (CDC) is robust against duplicates because it is based on data keys and change ordering — see and .

  • Data analytics users of the Data Lake are well advised to use curated data as a source for analytics. Raw event datasets materialized in the lake are typically cleaned-up (including deduplication and data synchronization) and provided as transactional data copy or curated data products, for instance curated product data [internal link] or curated sales data [internal link].

Context: One source of duplicate events are the event producers, for instance, due to publish call retries or publisher client failovers. Another source is Nakadi’s 'at-least-once' delivery promise (like provided by most message broker distributed systems). It also currently applies to the Data Lake event materialization as raw event datasets (in Delta or JSON format) for Data Analytics. From an event consumer point of view, duplicate events may also be created when consumers reprocess parts of the event stream, for instance, due to inaccurate continuation after failures. Event publishers and infrastructure systems should keep event duplication at a minimum typically below per-mille range. (In Nov. 2022, for instance, we observed <0.2 ‰ daily event duplicate rate (95th percentile) for high volume events.)

Events that are designed for out-of-order processing allow for extremely resilient systems: If processing an event fails, consumers and producers can skip/delay/retry it without stopping the world or corrupting the processing result.

To enable this freedom of processing, you must explicitly design for idempotent out-of-order processing: Either your events must contain enough information to infer their original order during consumption or your domain must be designed in a way that order becomes irrelevant.

As common example similar to data change events, idempotent out-of-order processing can be supported by sending the following information:

  • the process/resource/entity identifier,

  • a and

  • the process/resource state after the change.

A receiver that is interested in the current state can then ignore events that are older than the last processed event of each resource. A receiver interested in the history of a resource can use the ordering key to recreate a (partially) ordered sequence of events.

Events are intended to be used by other services including business process/data analytics and monitoring. They should be based around the resources and business processes you have defined for your service domain and adhere to its natural lifecycle (see also and ).

As there is a cost in creating an explosion of event types and topics, prefer to define event types that are abstract/generic enough to be valuable for multiple use cases, and avoid publishing event types without a clear need.

A data change event’s representation of an entity should correspond to the REST API representation.

There’s value in having the fewest number of published structures for a service. Consumers of the service will be working with fewer representations, and the service owners will have less API surface to maintain. In particular, you should only publish events that are interesting in the domain and abstract away from implementation or local details - there’s no need to reflect every change that happens within your system.

There are cases where it could make sense to define data change events that don’t directly correspond to your API resource representations. Some examples are -

  • Where the API resource representations are very different from the datastore representation, but the physical data are easier to reliably process for data integration.

  • Publishing aggregated data. For example a data change to an individual entity might cause an event to be published that contains a coarser representation than that defined for an API

  • Events that are the result of a computation, such as a matching algorithm, or the generation of enriched data, and which might not be stored as entity by the service.

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 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 is not available in JSON Schema)

This section collects links to documents to which we refer, and base our guidelines on.

  • OpenAPI specification

  • OpenAPI specification mind map

  • RFC 3339: Date and Time on the Internet: Timestamps

  • RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace

  • RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON)

  • RFC 8288: Web Linking

  • RFC 6585: Additional HTTP Status Codes

  • RFC 6902: JavaScript Object Notation (JSON) Patch

  • RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format

  • RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

  • RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

  • RFC 7232: Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests

  • RFC 7233: Hypertext Transfer Protocol (HTTP/1.1): Range Requests

  • RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching

  • RFC 7240: Prefer Header for HTTP

  • RFC 7396: JSON Merge Patch

  • RFC 7807: Problem Details for HTTP APIs

  • RFC 4648: The Base16, Base32, and Base64 Data Encodings

  • ISO 8601: Date and time format

  • ISO 3166-1 alpha-2: Two letter country codes

  • ISO 639-1: Two letter language codes

  • ISO 4217: Currency codes

  • BCP 47: Tags for Identifying Languages

  • Roy Thomas Fielding - Architectural Styles and the Design of Network-Based Software Architectures: This is the text which defines what REST is.

  • REST in Practice: Hypermedia and Systems Architecture

  • Build APIs You Won’t Hate

  • InfoQ eBook - Web APIs: From Start to Finish

  • Lessons-learned blog: Thoughts on RESTful API Design

This is not a part of the actual guidelines, but might be helpful for following them. Using a tool mentioned here doesn’t automatically ensure you follow the guidelines.

The following frameworks were specifically designed to support the API First workflow with OpenAPI YAML files (sorted alphabetically):

  • Connexion: OpenAPI First framework for Python on top of Flask

  • Friboo: utility library to write microservices in Clojure with support for Swagger and OAuth

  • Api-First-Hand: API-First Play Bootstrapping Tool for Swagger/OpenAPI specs

  • Swagger Codegen: template-driven engine to generate client code in different languages by parsing Swagger Resource Declaration

  • Swagger Codegen Tooling: plugin for Maven that generates pieces of code from OpenAPI specification

  • Swagger Plugin for IntelliJ IDEA: plugin to help you easily edit Swagger specification files inside IntelliJ IDEA

The Swagger/OpenAPI homepage lists more Community-Driven Language Integrations, but most of them do not fit our API First approach.

These utility libraries support you in implementing various parts of our RESTful API guidelines (sorted alphabetically):

  • Problem: Java library that implements application/problem+json

  • Problems for Spring Web MVC: library for handling Problems in Spring Web MVC

  • Jackson Datatype Money: extension module to properly support datatypes of javax.money

  • Tracer: call tracing and log correlation in distributed systems

  • TWINTIP Spring Integration: API discovery endpoint for Spring Web MVC

The best practices presented in this section are not part of the actual guidelines, but should provide guidance for common challenges we face when implementing RESTful APIs.

Cursor-based pagination is a very powerful and valuable technique (see also , that allows to efficiently provide a stable view on changing data. This is obtained by using an anchor element that allows to retrieve all page elements directly via an ordering combined-index, usually based on /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.89 or /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.91. Simple said, the cursor is the information set needed to reconstruct the database query to retrieves the minimal page information from the data storage.

The itself is an opaque string, transmitted forth and back between service and clients, that must never be inspected or constructed by clients. Therefore, it is good practice to encode (encrypt) its content in a non-human-readable form.

The content usually consists of a pointer to the anchor element defining the page position in the collection, a flag whether the element is included or excluded into/from the page, the retrieval direction, and a hash over the applied query filters (or the query filter itself) to safely re-create the collection. It is important to note, that a should be always defined in relation to the current page to anticipate all occurring changes when progressing.

The is usually defined as an encoding of the following information:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier4

Note: In case of complex and long search requests, e.g. when is already required, the may not be able to include the security: - BearerAuth: [ api-repository.read ]04 because of common HTTP parameter size restrictions. In this case the security: - BearerAuth: [ api-repository.read ]04 filters should be transported via body - in the request as well as in the response, while the pagination consistency should be ensured via the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.040.

Remark: It is also important to check the efficiency of the data-access. You need to make sure that you have a fully ordered stable index, that allows to efficiently resolve all elements of a page. If necessary, you need to provide a combined index that includes the openapi: 3.0.1 info: x-audience: company-internal title: Parcel Helper Service API description: API for <...> version: 1.2.4 <...>32 to ensure the full order and additional filter criteria to ensure efficiency.

  • Twitter

  • Use the Index, Luke

  • Paging in PostgreSQL

Optimistic locking might be used to avoid concurrent writes on the same entity, which might cause data loss. A client always has to retrieve a copy of an entity first and specifically update this one. If another version has been created in the meantime, the update should fail. In order to make this work, the client has to provide some kind of version reference, which is checked by the service, before the update is executed. Please read the more detailed description on how to update resources via in the .

A RESTful API usually includes some kind of search endpoint, which will then return a list of result entities. There are several ways to implement optimistic locking in combination with search endpoints which, depending on the approach chosen, might lead to performing additional requests to get the current version of the entity that should be updated.

An can only be obtained by performing a request on the single entity resource before the update, i.e. when using a search endpoint an additional request is necessary.

Example:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier5

Or, if there was an update since the and the entity’s has changed:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier6

  • RESTful solution

  • Many additional requests are necessary to build a meaningful front-end

The ETag for every entity is returned as an additional property of that entity. In a response containing multiple entities, every entity will then have a distinct that can be used in subsequent requests.

In this solution, the property should be /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.053 and never be expected in the request payload.

Example:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier7

Or, if there was an update since the and the entity’s has changed:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier6

  • Perfect optimistic locking

  • Information that only belongs in the HTTP header is part of the business objects

The entities contain a property with a version number. When an update is performed, this version number is given back to the service as part of the payload. The service performs a check on that version number to make sure it was not incremented since the consumer got the resource and performs the update, incrementing the version number.

Since this operation implies a modification of the resource by the service, a operation on the exact resource (e.g. /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.058) should be used instead of a .

In this solution, the /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.002 property is not /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.053 since it is provided at time as part of the payload.

Example:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier9

or if there was an update since the and the version number in the database is higher than the one given in the request body:

components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT0

  • Perfect optimistic locking

  • Functionality that belongs into the HTTP header becomes part of the business object

  • Using instead of PUT for an update logic (not a problem in itself, but may feel unusual for the consumer)

In HTTP 1.0 there was no and the mechanism used for optimistic locking was based on a date. This is still part of the HTTP protocol and can be used. Every response contains a header with a HTTP date. When requesting an update using a request, the client has to provide this value via the header . The server rejects the request, if the last modified date of the entity is after the given date in the header.

This effectively catches any situations where a change that happened between and would be overwritten. In the case of multiple result entities, the header will be set to the latest date of all the entities. This ensures that any change to any of the entities that happens between and will be detectable, without locking the rest of the batch as well.

Example:

components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT1

Or, if there was an update since the and the entities last modified is later than the given date:

<application-hostname> ::= <application-id>.<organization-unit>.zalan.do <application-id> ::= [a-z][a-z0-9-]* -- application identifier <organization-id> ::= [a-z][a-z0-9-]* -- organization unit identifier, e.g. team identifier6

  • Well established approach that has been working for a long time

  • No interference with the business objects; the locking is done via HTTP headers only

  • Very easy to implement

  • No additional request needed when updating an entity of a search endpoint result

  • If a client communicates with two different instances and their clocks are not perfectly in sync, the locking could potentially fail

We suggest to either use the in result entities or / approach.

This change log only contains major changes and lists major changes since October 2016.

Non-major changes are editorial-only changes or minor changes of existing guidelines, e.g. adding new error code or specific example. Major changes are changes that come with additional obligations, or even change an existing guideline obligation. Major changes are listed as "Rule Changes" below.

Hint: Most recent major changes might be missing in the list since we update it only occasionally, not with each pull request, to avoid merge commits. Please have a look at the commit list in Github to see a list of all changes.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.080: event id must not change in retry situations when producers .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.081: restructuring of the document and some rules.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.082: new rule .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.083: improve clarity on usage in rule .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.085: improve clarity on usage in rule .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.085: only use codes registered via IANA in rule .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.088: update formats per OpenAPI 3.1 in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.089: changed from SHOULD to MUST; consistency for rules around standards for data.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.090: with clear distinction of OpenAPI security schemes, favoring /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.40 to /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.41.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.093: resolve uncertainties around 'occurred_at' semantics of .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.094: with as only custom media type usage exception.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.095: define usage on resource-ids in and in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.098: improve clarity of .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.099: clarity on .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.100: changed from SHOULD to MUST; improve clarity around .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.099: best practice section

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.102: define how to reference models outside the api in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.103: improve guideline  — clients must be prepared to not receive problem return objects.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.104: more details for and ().

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.107: include models for headers to be included by reference in API definitions ()

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.108: add exception for legacy host names to

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.109: change from MUST to SHOULD, explain exceptions

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.109: add exception for /info/x-audience: type: string x-extensible-enum: - component-internal - business-unit-internal - company-internal - external-partner - external-public description: | Intended target audience of the API. Relevant for standards around quality of design and documentation, reviews, discoverability, changeability, and permission granting.36 to and .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.112: change "MUST avoid trailing slashes" to .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.113: change from MUST to SHOULD, mention gateway-specific headers (which are not part of the public API).

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.114: add details to

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.115: new sections about DELETE with query parameters and in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.117: new rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.118: add Sunset header, clarify deprecation producedure (, , , , , , )

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.123: new rule (as MUST, changed later to SHOULD)

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.124: change "Warning" to "Deprecation" header in , .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.129: remove never-implemented rule "MUST Permissions on events must correspond to API permissions"

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.130: remove duplicated rule "MAY Standards could be used for Language, Country and Currency", upgrade from MAY to SHOULD.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.131: new rule , extend pointing to RFC-7493

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.131: new rules ,

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.134: new rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.134: change from SHOULD to MUST

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.134: change "SHOULD Null values should have their fields removed to" .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.138: new rule .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.140: improved cursor guideline for .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.142: change from SHOULD to MUST, use OpenAPI 3 syntax

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.143: remove /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.144 from .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.145: add /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.146 to .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.147 New rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.148: New rule extracted + expanded from .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.150 Improve guidance on caching (, ).

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.154 Improve guidance on idempotency, introduce idempotency-key (, ).

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.158: Change from MAY to {SHOULD NOT}

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.159: Add /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.160 to event type definition schema (, )

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.161: New rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.162: replaced OpenAPI 2.0 syntax with OpenAPI 3.0 in the example snippets

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.163: New rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.164: Add /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.165 field to event type definition ()

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.166 Introduced new naming guidelines for host, permission, and event names.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.167 Moved meta information related aspects into new chapter .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.168 Changed publication requirements for API specifications ().

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.169 Added best practices section including discussion about optimistic locking approaches.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.170 Changed OAuth flow example from password to client credentials in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.171 Updated description of X-Tenant-ID header field

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.172 Migration to Asciidoc

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.173 Be more precise on client vs. server obligations for compatible API extensions.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.174 Made money object guideline clearer.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.175 Added guideline on query parameter collection format.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.176 Added the convention of using RFC2119 to describe guideline levels, and replaced /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.177 with /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.178.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.179 Added rule that permissions on resources in events must correspond to permissions on API resources

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.179 Added rule that APIs should be modelled around business processes

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.181 Extended information about how to reference sub-resources and the usage of composite identifiers in the part.

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.182 Added guidance for conditional requests with If-Match/If-None-Match

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.183 Added guideline for batch and bulk request

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.184

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.187 Removed "Avoid Javascript Keywords" rule

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.188 Clarification on the usage of the term "REST/RESTful"

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.189 Introduced "API as a Product" principle

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.190 New guideline: "Should Only Use UUIDs If Necessary"

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.191 Changed OAuth flow example from implicit to password in .

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.192

  • /info/x-api-id: type: string format: urn pattern: ^[a-z0-9][a-z0-9-:.]{6,62}[a-z0-9]$ description: | Mandatory globally unique and immutable API identifier. The API id allows to track the evolution and history of an API specification as a sequence of versions.193 Introduced the changelog. From now on all rule changes on API guidelines will be recorded here.

. Per definition of R.Fielding REST APIs have to support HATEOAS (maturity level 3). Our guidelines do not strongly advocate for full REST compliance, but limited hypermedia usage, e.g. for pagination (see ). However, we still use the term "RESTful API", due to the absence of an alternative established term and to keep it like the very majority of web service industry that also use the term for their REST approximations — in fact, in today’s industry full HATEOAS compliant APIs are a very rare exception.

. HTTP/1.1 standard () defines two types of headers: end-to-end and hop-by-hop headers. End-to-end headers must be transmitted to the ultimate recipient of a request or response. Hop-by-hop headers, on the contrary, are meaningful for a single connection only.

When passing procedure parameters on the stack why are the following lines of code often necessary in a procedure?\?

Terms in this set (39) When passing procedure parameters on the stack, why are the following lines of code often necessary in a procedure? To keep additional usage of the stack within the procedure from invalidating the stack offsets.

What type of tool can convert ARM assembly to x86 assembly?

What type of tool can convert ARM Assembly to x86 Assembly? Architecture's instructions are directly executed by the CPU. A program that combines object files into an executable program is called a linker .

Toplist

Neuester Beitrag

Stichworte