SOLR-11446: Heavily edit the 'near real time searching' page in the reference guide, fix doc build error

= Near Real Time Searching
:page-shortname: near-real-time-searching
:page-permalink: near-real-time-searching.html
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

Near Real Time (NRT) search means that documents are available for search soon after being indexed. NRT searching is one of the main features of SolrCloud and is rarely attempted in master/slave configurations.

Document durability and searchability are controlled by `commits`. The "Near" in "Near Real Time" is configurable to meet the needs of your application. Commits are either "hard" or "soft" and can be issued by a client (say SolrJ), via a REST call or configured to occur automatically in solrconfig.xml. The recommendation usually gives is to configure your commit strategy in solrconfig.xml (see below) and avoid issuing commits externally.

Typically in NRT applications, hard commits are configured with `openSearcher=false`, and soft commits are configured to make documents visible for search.

When a commit occurs, various background tasks are initiated, segment merging for example. These background tasks do not block additional updates to the index nor do they delay the availability of the documents for search.

When configuring for NRT, pay special attention to cache and autowarm settings as they can have a significant impact on NRT performance. For extremely short autoCommit intervals, consider disabling caching and autowarming completely.

== Commits and Searching

A *hard commit* calls `fsync` on the index files to ensure they have been flushed to stable storage. The current transaction log is closed and a new one is opened. See the "transaction log" discussion below for how data is recovered in the absence of a hard commit. Optionally a hard commit can also make documents visible for search, but this is not recommended for NRT searching as it is more expensive than a soft commit.

A *soft commit* is faster since it only makes index changes visible and does not `fsync` index files, start a new segment or start a new transaction log. Search collections that have NRT requirements will want to soft commit often enough to satisfy the visibility requirements of the application. A softCommit may be "less expensive" than a hard commit (openSearcher=true), but it is not free. It is recommended that this be set for as long as is reasonable given the application requirements.

Both hard and soft commits have two primary configuration parameters: `maxDocs` and `maxTime`.

`maxDocs`::
Integer. Defines the number of updates to process before activating.

`maxTime`::
Integer. The number of milliseconds to wait before activating.

If both of these parameters are specified, the first one to expire is honored. Generally, it is preferred to use `maxTime` rather than `maxDocs`, especially when indexing large numbers of documents in batches. Use `maxDocs` and `maxTime` judiciously to fine-tune your commit strategies.

Hard commit has an additional parameter `openSearcher`

`openSearcher`::
true|false, whether to make documents visible for search. For NRT applications this is usually set to `false` and `soft commit` is configured to control when documents are visible for search.

=== Transaction Logs (tlogs)

Transaction logs are a "rolling window" of updates since the last hard commit. The current transaction log is closed and a new one opened each time any variety of hard commit occurs. Soft commits have no effect on the transaction log.

When tlogs are enabled, documents being added to the index are written to the tlog before the indexing call returns to the client. In the event of an un-graceful shutdown (power loss, JVM crash, `kill -9` etc) any documents written to the tlog but not yet committed with a hard commit when Solr was stopped are replayed on startup. Therefore the data is not lost.

When Solr is shut down gracefully (using the `bin/solr stop` command) Solr will close the tlog file and index segments so no replay will be necessary on startup.

One point of confusion is how much data is contained in a tlog. A tlog does not contain all documents, just the ones since the last hard commit. There are come low-level details involving `peer sync` that also involve the tlogs that are not relevant to this discussion. Older tlogs are deleted when no longer needed.

WARNING: Implicit in the above is that transaction logs will grow forever if hard commits are disabled. Therefore it is important that hard commits be enabled when indexing.

=== Configuring commits

As mentioned above, it is usually preferable to configure your commits (both hard and soft) in solrconfig.xml and avoid sending commits from an external source. Check your `solrconfig.xml` file since the defaults are likely not tuned to your needs. Here is an example NRT configuration for the two flavors of commit, a hard commit every 60 seconds and a soft commit every 30 seconds. Note that these are _not_ the values in some of the examples!

[source,xml]
----
<autoCommit>
  <maxTime>${solr.autoCommit.maxTime:60000}</maxTime>
  <openSearcher>false</openSearcher>
</autoCommit>

<autoSoftCommit>
   <maxTime>${solr.autoSoftCommit.maxTime:30000}</maxTime>
 </autoSoftCommit>
----

TIP: These parameters can be overridden at run time by defining Java "system variables", for example specifying ``-Dsolr.autoCommit.maxTime=15000` would override the hard commit interval with a value of 15 seconds.

The choices for `autoCommit` (with `openSearcher=false`) and `autoSoftCommit` have different consequences. In the event of un-graceful shutdown, it can take up to the time specified in `autoCommit` for Solr to replay the uncommitted documents from the transaction log.

The time chosen for `autoSoftCommit` determines the maximum time after a document is sent to Solr before it becomes searchable and does not affect the transaction log. Choose as long an interval as your application can tolerate for this value, often 15-60 seconds is reasonable, or even longer depending on the requirements. In situations where the the time is set to a very short interval (say 1 second), consider disabling your caches (queryResultCache and filterCache especially) as they will have little utility.

TIP: For extremely high bulk indexing, especially for the initial load if there is no searching, consider turning off `autoSoftCommit` by specifying a value of `-1` for the maxTime parameter.

== Advanced Commit Options

All varieties of commits can be invoked from a SolrJ client or via a URL. The usual recommendation is to _not_ call commits externally. For those cases where it is desirable, see <<uploading-data-with-index-handlers.adoc#xml-update-commands,Update Commands>>. These options are listed for XML update commands that can be issued from a browser or curl etc and the equivalents are available from a SolrJ client.

= Near Real Time Searching
:page-shortname: near-real-time-searching
:page-permalink: near-real-time-searching.html
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

Near Real Time (NRT) search means that documents are available for search soon after being indexed. NRT searching is one of the main features of SolrCloud and is rarely attempted in master/slave configurations.

Document durability and searchability are controlled by `commits`. The "Near" in "Near Real Time" is configurable to meet the needs of your application. Commits are either "hard" or "soft" and can be issued by a client (say SolrJ), via a REST call or configured to occur automatically in solrconfig.xml. The recommendation usually gives is to configure your commit strategy in solrconfig.xml (see below) and avoid issuing commits externally.

Typically in NRT applications, hard commits are configured with `openSearcher=false`, and soft commits are configured to make documents visible for search.

When a commit occurs, various background tasks are initiated, segment merging for example. These background tasks do not block additional updates to the index nor do they delay the availability of the documents for search.

When configuring for NRT, pay special attention to cache and autowarm settings as they can have a significant impact on NRT performance. For extremely short autoCommit intervals, consider disabling caching and autowarming completely.

== Commits and Searching

A *hard commit* calls `fsync` on the index files to ensure they have been flushed to stable storage. The current transaction log is closed and a new one is opened. See the "transaction log" discussion below for how data is recovered in the absence of a hard commit. Optionally a hard commit can also make documents visible for search, but this is not recommended for NRT searching as it is more expensive than a soft commit.

A *soft commit* is faster since it only makes index changes visible and does not `fsync` index files, start a new segment or start a new transaction log. Search collections that have NRT requirements will want to soft commit often enough to satisfy the visibility requirements of the application. A softCommit may be "less expensive" than a hard commit (openSearcher=true), but it is not free. It is recommended that this be set for as long as is reasonable given the application requirements.

Both hard and soft commits have two primary configuration parameters: `maxDocs` and `maxTime`.

`maxDocs`::
Integer. Defines the number of updates to process before activating.

`maxTime`::
Integer. The number of milliseconds to wait before activating.

If both of these parameters are specified, the first one to expire is honored. Generally, it is preferred to use `maxTime` rather than `maxDocs`, especially when indexing large numbers of documents in batches. Use `maxDocs` and `maxTime` judiciously to fine-tune your commit strategies.

Hard commit has an additional parameter `openSearcher`

`openSearcher`::
true|false, whether to make documents visible for search. For NRT applications this is usually set to `false` and `soft commit` is configured to control when documents are visible for search.

=== Transaction Logs (tlogs)

Transaction logs are a "rolling window" of updates since the last hard commit. The current transaction log is closed and a new one opened each time any variety of hard commit occurs. Soft commits have no effect on the transaction log.

When tlogs are enabled, documents being added to the index are written to the tlog before the indexing call returns to the client. In the event of an un-graceful shutdown (power loss, JVM crash, `kill -9` etc) any documents written to the tlog but not yet committed with a hard commit when Solr was stopped are replayed on startup. Therefore the data is not lost.

When Solr is shut down gracefully (using the `bin/solr stop` command) Solr will close the tlog file and index segments so no replay will be necessary on startup.

One point of confusion is how much data is contained in a tlog. A tlog does not contain all documents, just the ones since the last hard commit. There are come low-level details involving `peer sync` that also involve the tlogs that are not relevant to this discussion. Older tlogs are deleted when no longer needed.

WARNING: Implicit in the above is that transaction logs will grow forever if hard commits are disabled. Therefore it is important that hard commits be enabled when indexing.

=== Configuring commits

As mentioned above, it is usually preferable to configure your commits (both hard and soft) in solrconfig.xml and avoid sending commits from an external source. Check your `solrconfig.xml` file since the defaults are likely not tuned to your needs. Here is an example NRT configuration for the two flavors of commit, a hard commit every 60 seconds and a soft commit every 30 seconds. Note that these are _not_ the values in some of the examples!

[source,xml]
----
<autoCommit>
  <maxTime>${solr.autoCommit.maxTime:60000}</maxTime>
  <openSearcher>false</openSearcher>
</autoCommit>

<autoSoftCommit>
   <maxTime>${solr.autoSoftCommit.maxTime:30000}</maxTime>
 </autoSoftCommit>
----

TIP: These parameters can be overridden at run time by defining Java "system variables", for example specifying ``-Dsolr.autoCommit.maxTime=15000` would override the hard commit interval with a value of 15 seconds.

The choices for `autoCommit` (with `openSearcher=false`) and `autoSoftCommit` have different consequences. In the event of un-graceful shutdown, it can take up to the time specified in `autoCommit` for Solr to replay the uncommitted documents from the transaction log.

The time chosen for `autoSoftCommit` determines the maximum time after a document is sent to Solr before it becomes searchable and does not affect the transaction log. Choose as long an interval as your application can tolerate for this value, often 15-60 seconds is reasonable, or even longer depending on the requirements. In situations where the the time is set to a very short interval (say 1 second), consider disabling your caches (queryResultCache and filterCache especially) as they will have little utility.

TIP: For extremely high bulk indexing, especially for the initial load if there is no searching, consider turning off `autoSoftCommit` by specifying a value of `-1` for the maxTime parameter.

== Advanced Options

All varieties of commits can be invoked from a SolrJ client or via a URL. The usual recommendation is to _not_ call commits externally. For those cases where it is desirable, see <<uploading-data-with-index-handlers.adoc#xml-update-commands,Update Commands>>. These options are listed for XML update commands that can be issued from a browser or curl etc and the equivalents are available from a SolrJ client.


Fixing format

Fixing format

Signed-off-by: Arthur De Magalhaes <59d841a66e711472460ddee2e788b052b3849e47@gmail.com>

//
// Copyright (c) 2017 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

:sectanchors:
:doctype: book
:license: Apache License v2.0
:source-highlighter: coderay
:sectnums:
:toc: left
:toclevels: 4
ifdef::backend-pdf[]
:pagenums:
endif::[]

= MicroProfile OpenAPI Specification

include::license-alv2.asciidoc[]

== Introduction
Exposing APIs has become an essential part of all modern applications.  At the
center of this revolution known as the API Economy we find RESTful APIs, which can
transform any application into language agnostic services that can be called from
anywhere: on-premises, private cloud, public cloud, etc.

For the clients and providers of these services to connect there needs to be a
clear and complete contract.  Similar to the WSDL contract for legacy Web Services,
the https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md[OpenAPI v3] specification is the contract for
RESTful Services.

This MicroProfile specification, called OpenAPI 1.0, aims to provide a set of Java
interfaces and programming models which allow Java developers to natively produce
OpenAPI v3 documents from their JAX-RS applications.

== Architecture

There are different ways to augment a JAX-RS application in order to produce an
OpenAPI document, which are described in <<Documentation Mechanisms>>.  The picture
below provides a quick overview of the different types of components that make up
the MP OpenAPI specification:

:imagesdir: images
image::diagram.png[Architecture Diagram]

The remaining sections of this specification will go into the details of each component.

== Configuration

Configuration of various parts of this specification is provided via the https://github.com/eclipse/microprofile-config[MicroProfile Config] mechanism,
which means that vendors implementing the MP OpenAPI specification must also implement
the MP Config specification.

There are various ways to inject these configuration values into an MP OpenAPI
framework, including the https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#default-configources[default ConfigSource] as well as
https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#custom-configsources[custom ConfigSource].

Vendors implementing the MP OpenAPI specification can optionally provide additional native
ways for these configuration values to be injected into the framework
(e.g. via a server configuration file), as long as they also implement the MP Config
specification.

=== List of configurable items

Vendors must support all the <<Core configurations>> of this specification.
Optionally, they may also support <<Vendor extensions>> that allow the configuration of
framework-specific values for configurations that affect implementation behavior.

For convenience of vendors (and application developers using custom ConfigSources),
the full list of supported configuration keys is available as constants in the
https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASConfig.java[OASConfig] class.

==== Core configurations

The following is a list of configuration values that every vendor must support.

[cols="1,4"]
|===
| Config key | Value description

| `mp.openapi.model.reader` | Configuration property to specify the fully qualified name of the <<OASModelReader>> implementation.
| `mp.openapi.filter` | Configuration property to specify the fully qualified name of the <<OASFilter>> implementation.
| `mp.openapi.scan.disable`  |  Configuration property to disable annotation scanning. Default value is `false`.
| `mp.openapi.scan.packages`  |  Configuration property to specify the list of packages to scan. For example,
`mp.openapi.scan.packages=com.xyz.PackageA,com.xyz.PackageB`
| `mp.openapi.scan.classes`  |  Configuration property to specify the list of classes to scan. For example,
`mp.openapi.scan.classes=com.xyz.MyClassA,com.xyz.MyClassB`
| `mp.openapi.scan.exclude.packages`  |  Configuration property to specify the list of packages to exclude from scans. For example,
`mp.openapi.scan.exclude.packages=com.xyz.PackageC,com.xyz.PackageD`
| `mp.openapi.scan.exclude.classes`  |  Configuration property to specify the list of classes to exclude from scans. For example,
`mp.openapi.scan.exclude.classes=com.xyz.MyClassC,com.xyz.MyClassD`
| `mp.openapi.servers`  |  Configuration property to specify the list of global servers that provide connectivity information. For example,
`mp.openapi.servers=https://xyz.com/v1,https://abc.com/v1`
| `mp.openapi.servers.path.`   |  Prefix of the configuration property to specify an alternative list of servers to service all operations in a path. For example,
`mp.openapi.servers.path./airlines/bookings/{id}=https://xyz.io/v1`
| `mp.openapi.servers.operation.` | Prefix of the configuration property to specify an alternative list of servers to service an operation.
Operations that want to specify an alternative list of servers must define an `operationId`, a unique string used to identify the operation. For example,
`mp.openapi.servers.operation.getBooking=https://abc.io/v1`
|===

==== Vendor extensions

Vendors that wish to provide vendor-specific configuration via MP Config (instead
of another native configuration framework) must use the prefix `mp.openapi.extensions`.

== Documentation Mechanisms

There are many different ways to provide input for the generation of the resulting
OpenAPI document.

The MP OpenAPI specification requires vendors to produce a valid OpenAPI document
from pure JAX-RS 2.0 applications.  This means that vendors must process all the
relevant JAX-RS annotations (such as `@Path` and `@Consumes`) as well as Java objects
(POJOs) used as input or output to JAX-RS operations.  This is a good place to
start for application developers that are new to OpenAPI: just deploy your existing
JAX-RS application into a MP OpenAPI vendor and check out the output from `/openapi`!

The application developer then has a few choices:

1.  Augment those JAX-RS annotations with the
OpenAPI <<Annotations>>.  Using annotations means
developers don't have to re-write the portions of the OpenAPI document that are
already covered by the JAX-RS framework (e.g. the HTTP method of an operation).

2. Take the initial output from `/openapi` as a starting point to document
your APIs via <<Static OpenAPI files>>.  It's worth mentioning that these static
files can also be written before any code, which is an approach often adopted by
enterprises that want to lock-in the contract of the API.  In this case, we refer
to the OpenAPI document as the "source of truth", by which the client and provider
must abide.

3. Use the <<Programming model>> to provide a bootstrap (or complete)
OpenAPI model tree.

Additionally, a <<Filter>> is described which can update the OpenAPI model after it has
been built from the previously described documentation mechanisms.

=== Annotations

Many of these OpenAPI v3 annotations were derived from the https://github.com/swagger-api/swagger-core[Swagger Core] library, which
allows for a mostly-mechanical transformation of applications that are using that
library and wish to take advantage to the official MP OpenAPI interfaces.

==== Quick overview of annotations

The following annotations are found in the https://github.com/eclipse/microprofile-open-api/tree/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations[org.eclipse.microprofile.openapi.annotations] package.

[cols="1,4"]
|===
| Annotation | Description

| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java[@Callback] | Represents a callback URL that will be invoked.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callbacks.java[@Callbacks] | Represents an array of Callback URLs that can be invoked.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/CallbackOperation.java[@CallbackOperation] | Represents an operation that will be invoked during the callback.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/Components.java[@Components] | A container that holds various reusable objects for different aspects of the OpenAPI Specification.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/Explode.java[@Explode] | Enumeration used to define the value of the `explode` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/ParameterIn.java[@ParameterIn] | Enumeration representing the parameter's `in` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/ParameterStyle.java[@ParameterStyle] | Enumeration for the parameter's `style` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/SecuritySchemeIn.java[@SecuritySchemeIn] | Enumeration for the security scheme's `in` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/SecuritySchemeType.java[@SecuritySchemeType] | Enumeration for the security scheme's `type` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/extensions/Extension.java[@Extension] | Adds an extension with contained properties.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/extension/Extensions.java[@Extensions] | Adds custom properties to an extension.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/ExternalDocumentation.java[@ExternalDocumentation] | References an external resource for extended documentation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java[@Header] | Describes a single header object.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/Contact.java[@Contact] | Contact information for the exposed API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/Info.java[@Info] | This annotation encapsulates metadata about the API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/License.java[@License] | License information for the exposed API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java[@Link] | Represents a design-time link for a response.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/LinkParameter.java[@LinkParameter] | Represents a parameter to pass to the linked operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Content.java[@Content] | Provides schema and examples for a particular media type.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DiscriminatorMapping.java[@DiscriminatorMapping] | Used to differentiate between other schemas which may satisfy the payload description.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Encoding.java[@Encoding] | Single encoding definition to be applied to single Schema Object.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java[@ExampleObject] | Illustrates an example of a particular content.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java[@Schema] | Allows the definition of input and output data types.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/OpenAPIDefinition.java[@OpenAPIDefinition] | General metadata for an OpenAPI definition.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/Operation.java[@Operation] | Describes an operation or typically a HTTP method against a specific path.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java[@Parameter] | Describes a single operation parameter.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameters.java[@Parameters] | Encapsulates input parameters.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java[@RequestBody] | Describes a single request body.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/response/APIResponse.java[@APIResponse] | Describes a single response from an API operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/response/APIResponses.java[@APIResponses] | A container for multiple responses from an API operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthFlow.java[@OAuthFlow] | Configuration details for a supported OAuth Flow.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthFlows.java[@OAuthFlows] | Allows configuration of the supported OAuth Flows.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthScope.java[@OAuthScope] | Represents an OAuth scope.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirement.java[@SecurityRequirement] |  Specifies a security requirement for an operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirements.java[@SecurityRequirements] | Represents an array of security requirements where only one needs to be satisfied.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirementsSet.java[@SecurityRequirementsSet] | Represents an array of security requirements that need to be satisfied.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java[@SecurityScheme] |  Defines a security scheme that can be used by the operations.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecuritySchemes.java[@SecuritySchemes] | Represents an array of security schemes that can be specified.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/Server.java[@Server]|  Represents a server used in an operation or used by all operations in an OpenAPI document.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/Servers.java[@Servers] | A container for multiple server definitions.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java[@ServerVariable] | Represents a server variable for server URL template substitution.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java[@Tag] | Represents a tag for the API endpoint.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tags.java[@Tags] | A container of multiple tags.
|===

==== Detailed usage of key annotations

===== Operation

.Sample 1 - Simple operation description
[source,Java]
----
@GET
@Path("/findByStatus")
@Operation(summary = "Finds Pets by status",
           description = "Multiple status values can be provided with comma separated strings")
public Response findPetsByStatus(...) { ... }
----

.Output for Sample 1
[source, yaml]
----
/pet/findByStatus:
  get:
    summary: Finds Pets by status
    description: Multiple status values can be provided with comma separated strings
    operationId: findPetsByStatus
----

.Sample 2 - Operation with different responses
[source,Java]
----
@GET
@Path("/{username}")
@Operation(summary = "Get user by user name")
@APIResponse(description = "The user",
             content = @Content(mediaType = "application/json",
                                schema = @Schema(implementation = User.class))),
@APIResponse(responseCode = "400", description = "User not found")
public Response getUserByName(
        @Parameter(description = "The name that needs to be fetched. Use user1 for testing. ", required = true) @PathParam("username") String username)
 {...}
----

.Output for Sample 2
[source, yaml]
----
/user/{username}:
    get:
      summary: Get user by user name
      operationId: getUserByName
      parameters:
      - name: username
        in: path
        description: 'The name that needs to be fetched. Use user1 for testing. '
        required: true
        schema:
          type: string
      responses:
        default:
          description: The user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        400:
          description: User not found
----

===== RequestBody

.Sample 1 - Simple RequestBody
[source,Java]
----
@POST
@Path("/user")
@Operation(summary = "Create user",
           description = "This can only be done by the logged in user.")
public Response methodWithRequestBody(
          @RequestBody(description = "Created user object", required = true,
                       content = @Content(schema = @Schema(implementation = User.class))) User user,
          @QueryParam("name") String name, @QueryParam("code") String code)
          { ... }
----

.Output for Sample 1
[source, yaml]
----
post:
    summary: Create user
      description: This can only be done by the logged in user.
      operationId: methodWithRequestBody
    parameters:
    - name: name
      in: query
      schema:
      type: string
    - name: code
      in: query
      schema:
      type: string
    requestBody:
      description: Created user object
      content:
       '*/*':
        schema:
          $ref: '#/components/schemas/User'
          required: true
    responses:
      default:
        description: no description
----

===== Servers

.Sample 1 - Extended Server scenarios
[source,Java]
----
@OpenAPIDefinition(
    servers = {
        @Server(
            description = "definition server 1",
            url = "http://{var1}.definition1/{var2}",
            variables = {
                @ServerVariable(name = "var1",
                                description = "var 1",
                                defaultValue = "1",
                                enumeration = {"1", "2"}),
                @ServerVariable(name = "var2",
                                description = "var 2",
                                defaultValue = "1",
                                enumeration = {"1", "2"})})})
@Server(
    description = "class server 1",
    url = "http://{var1}.class1/{var2}",
    variables = {
            @ServerVariable(
                      name = "var1",
                      description = "var 1",
                      defaultValue = "1",
                      enumeration = {"1", "2"}),
            @ServerVariable(
                      name = "var2",
                      description = "var 2",
                      defaultValue = "1",
                      enumeration = {"1", "2"})})
@Server(
    description = "class server 2",
    url = "http://{var1}.class2",
    variables = {
            @ServerVariable(
                       name = "var1",
                       description = "var 1",
                       defaultValue = "1",
                       enumeration = {"1", "2"})})
public class ServersResource {

    @GET
    @Path("/")
    @Server(
        description = "method server 1",
        url = "http://{var1}.method1",
        variables = {
            @ServerVariable(
                      name = "var1",
                      description = "var 1",
                      defaultValue = "1",
                      enumeration = {"1", "2"})})
    @Server(
        description = "method server 2",
        url = "http://method2"
    )
    public Response getServers() {
        return Response.ok().entity("ok").build();
    }
}
----

.Output for Sample 1
[source, yaml]
----
openapi: 3.0.0
servers:
- url: http://{var1}.definition1/{var2}
  description: definition server 1
  variables:
    var1:
      description: var 1
      enum:
      - "1"
      - "2"
      default: "1"
    var2:
      description: var 2
      enum:
      - "1"
      - "2"
      default: "1"
paths:
  /:
    get:
      operationId: getServers
      responses:
        default:
          description: default response
      servers:
      - url: http://{var1}.class1/{var2}
        description: class server 1
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
          var2:
            description: var 2
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://{var1}.class2
        description: class server 2
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://{var1}.method1
        description: method server 1
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://method2
        description: method server 2
        variables: {}
----

===== Schema

.Sample 1 - Schema POJO
[source,Java]
----
@Schema(name="MyBooking", description="POJO that represents a booking.")
public class Booking {
    @Schema(required = true, example = "32126319")
    private String airMiles;

    @Schema(required = true, example = "window")
    private String seatPreference;
}
----

.Output for Sample 1
[source, yaml]
----
components:
  schemas:
    MyBooking:
      description: POJO that represents a booking.
      required:
      - airMiles
      - seatPreference
      type: object
      properties:
        airMiles:
          type: string
          example: "32126319"
        seatPreference:
          type: string
          example: window
----

.Sample 2 - Schema POJO reference
[source,Java]
----
@POST
public Response createBooking(
     @RequestBody(description = "Create a new booking.",
                  content = @Content(mediaType = "application/json",
                                     schema = @Schema(implementation = Booking.class))) Booking booking) {
----

.Output for Sample 2
[source, yaml]
----
post:
  operationId: createBooking
  requestBody:
    description: Create a new booking with the provided information.
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/MyBooking'
----

For more samples please see the https://github.com/eclipse/microprofile-open-api/wiki[MicroProfile Wiki].

=== Static OpenAPI files

Application developers may wish to include a pre-generated OpenAPI document that
was written separately from the code (e.g. with an editor such as https://editor.swagger.io/[this]).

Depending on the scenario, the document may be fully complete or partially complete.
If a document is fully complete then the application developer will want to set the
`mp.openapi.scan.disable` configuration property to `true`.  If a document is partially
complete, then the application developer will need to augment the OpenAPI snippet
with annotations, programming model, or via the filter.

==== Location and formats

Vendors are required to fetch a single document named `openapi` with an extension
of `yml`, `yaml` or `json`, inside the application's `META-INF` folder.  If there
is more than one document found that matches one of these extensions the behavior
of which file is chosen is undefined (i.e. each vendor may implement their own logic),
which means that application developers should only place a single `openapi` document
into that folder.

=== Programming model

Application developers are able to provide OpenAPI elements via Java POJOs. The
complete set of models are found in the https://github.com/eclipse/microprofile-open-api/tree/master/api/src/main/java/org/eclipse/microprofile/openapi/models[org.eclipse.microprofile.openapi.models] package.

==== OASFactory

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASFactory.java[OASFactory] is used to create all of the elements of an OpenAPI tree.

For example, the following snippet creates a simple https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/models/info/Info.java[Info] element that contains a title, description, and version.

[source,java]
----
OASFactory.createObject(Info.class).title("Airlines").description("Airlines APIs").version("1.0.0");
----

==== OASModelReader

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASModelReader.java[OASModelReader] interface allows application developers to bootstrap the OpenAPI model tree
used by the processing framework.  To use it, simply create an implementation of
this interface and register it using the `mp.openapi.model.reader` configuration
key, where the value is the fully qualified name of the reader class.

.Sample META-INF/microprofile-config.properties
[code,property]
----
mp.openapi.model.reader=com.mypackage.MyModelReader
----

Similar to static files, the model reader can be used to provide either complete
or partial model trees. If providing a complete OpenAPI model tree, application
developers should set the `mp.openapi.scan.disable` configuration to `true`.
Oherwise this partial model will be used as the base model during the processing
of the other <<Documentation Mechanisms>>.

Vendors are required to call the OASReader a single time, in the order defined by
the <<Processing rules>> section.  Only a single OASReader instance is allowed per
application.

=== Filter

There are many scenarios where application developers may wish to update or remove
certain elements and fields of the OpenAPI document.  This is done via a filter,
which is called once after all other documentation mechanisms have completed.

==== OASFilter

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASFilter.java[OASFilter] interface allows application developers
to receive callbacks for various key OpenAPI elements.  The interface has a default
implementation for every method, which allows application developers to only override
the methods they care about.  To use it, simply create an implementation of
this interface and register it using the `mp.openapi.filter` configuration
key, where the value is the fully qualified name of the filter class.

.Sample META-INF/microprofile-config.properties
[code,property]
----
mp.openapi.filter=com.mypackage.MyFilter
----

Vendors are required to call all registered filters in the application (0..N) once
for each filtered element.  For example, the method `filterPathItem` is
called *for each* corresponding `PathItem` element in the model tree.  This allows
application developers to filter the element and any of its descendants.

The order of filter methods called is undefined, with two exceptions:

1.  All filterable descendant elements of a filtered element must be called before its ancestor.
2.  The `filterOpenAPI` method must be the *last* method called on a filter (which
is just a specialization of the first exception).

=== Processing rules

The processed document available from the <<OpenAPI Endpoint>> is built from a variety of sources,
which were outlined in the sub-headings of <<Documentation Mechanisms>>.  Vendors
are required to process these different sources in the following order:

1. Fetch configuration values from `mp.openapi` namespace
2. Call OASModelReader
3. Fetch static OpenAPI file
4. Process annotations
5. Filter model via OASFilter

**Example processing**:

* A vendor starts by fetching all available <<Configuration>>.  If
an `OASModelReader` was specified in that configuration list, its `buildModel`
method is called to form the starting OpenAPI model tree for this application.
* Any <<Vendor specific configuration>> are added on top of that starting model (overriding
conflicts), or create a new model if an `OASModelReader` was not registered.
* The vendor searches for a file as defined in the section <<Static OpenAPI files>>.
If found, it will read that document and merge with the model produced by previous
processing steps (if any), where conflicting elements from the static file will override
the values from the original model.
* If annotation scanning was not disabled, the JAX-RS and OpenAPI annotations from
the application will be processed, further overriding any conflicting elements
from the current model.
* The final model is filtered by walking the model tree and invoking all registered
<<OASFilter>> classes.

== OpenAPI Endpoint

=== Overview
A fully processed and valid OpenAPI document must be available at the root
URL `/openapi`, as a `HTTP GET` operation.

For example, `GET http://myHost:myPort/openapi`.

This document represents the result of the applied <<Processing rules>>.

The protocol required is `http`.  Vendors are encouraged, but not required, to
support the `https` protocol as well, to enable a secure connection to the OpenAPI
endpoint.

=== Content format
The default format of the `/openapi` endpoint is `YAML`.

Vendors must also support the `JSON` format if the request contains an `Accept`
header with a value of `application/json`, in which case the response must contain
a `Content-Type` header with value of `application/json`.

=== Query parameters
No query parameters are required for the `/openapi` endpoint.  However, one
suggested but optional query parameter for vendors to support is `format`,
where the value can be either `json` or `yaml`, to facilitate the toggle between
the default `yaml` format and `json` format.

=== Context root behaviour
Vendors are required to ensure that the combination of each global https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#serverObject[server]
element and https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject[pathItem] element resolve to the absolute backend URL of that
particular path.  If that `pathItem` contains a `servers` element , then this
list of operation-level `server` elements replaces the global list of servers
for that particular `pathItem`.

For example:  an application may have an `ApplicationPath` annotation with the
value of `/`, but is assigned the context root of `/myApp` during deployment. In
this case, the `server` elements (either global or operation-level) must either
end with `/myApp` or a corresponding proxy.  Alternatively it is valid, but discouraged, to
add that context root (`/myApp`) to every `pathItem` defined in that application.

=== Multiple applications

The 1.0 version of the MicroProfile OpenAPI specification does not define how
the `/openapi` endpoint may be partitioned in the event that the MicroProfile
runtime supports deployment of multiple applications. If an implementation wishes
to support multiple applications within a MicroProfile runtime, the semantics of
the `/openapi` endpoint are expected to be the logical AND of all the applications
in the runtime, which would imply merging multiple OpenAPI documents into a single
valid document (handling conflicting IDs and unique names).

== Limitations

=== Internationalization
The 1.0 version of the MicroProfile OpenAPI spec does not require vendors to
support multiple languages based on the `Accept-Language`.  One reasonable
approach is for vendors to support unique keys (instead of hardcoded text) via
the various <<Documentation Mechanisms>>, so that the implementing framework can
perform a global replacement of the keys with the language-specific text that
matches the `Accept-Language` request for the `/openapi` endpoint.  A cache of
processed languages can be kept to improve performance.

=== Validation

The MP OpenAPI 1.0 specification does not mandate vendors to validate the resulting
OpenAPI v3 model (after processing the 5 steps previously mentioned), which means
that the behavior of invalid models is vendor specific (i.e. vendors may choose to
ignore, reject, or pass-through invalid inputs).

=== Cross Origin Resource Sharing (CORS)

The MP OpenAPI 1.0 specification does not require vendors to support https://www.w3.org/TR/cors/[CORS]
for the `/openapi` endpoint.  The behavior of CORS requests is implementation dependent.

include::release_notes.asciidoc[]

//
// Copyright (c) 2017 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

:version-label!:
:sectanchors:
:doctype: book
:license: Apache License v2.0
:source-highlighter: coderay
:sectnums:
:toc: left
:toclevels: 4
ifdef::backend-pdf[]
:pagenums:
endif::[]

include::license-alv2.asciidoc[]

= MicroProfile OpenAPI Specification

== Introduction
Exposing APIs has become an essential part of all modern applications.  At the
center of this revolution known as the API Economy we find RESTful APIs, which can
transform any application into language agnostic services that can be called from
anywhere: on-premises, private cloud, public cloud, etc.

For the clients and providers of these services to connect there needs to be a
clear and complete contract.  Similar to the WSDL contract for legacy Web Services,
the https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md[OpenAPI v3] specification is the contract for
RESTful Services.

This MicroProfile specification, called OpenAPI 1.0, aims to provide a set of Java
interfaces and programming models which allow Java developers to natively produce
OpenAPI v3 documents from their JAX-RS applications.

== Architecture

There are different ways to augment a JAX-RS application in order to produce an
OpenAPI document, which are described in <<Documentation Mechanisms>>.  The picture
below provides a quick overview of the different types of components that make up
the MP OpenAPI specification:

:imagesdir: images
image::diagram.png[Architecture Diagram]

The remaining sections of this specification will go into the details of each component.

== Configuration

Configuration of various parts of this specification is provided via the https://github.com/eclipse/microprofile-config[MicroProfile Config] mechanism,
which means that vendors implementing the MP OpenAPI specification must also implement
the MP Config specification.

There are various ways to inject these configuration values into an MP OpenAPI
framework, including the https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#default-configources[default ConfigSource] as well as
https://github.com/eclipse/microprofile-config/blob/master/spec/src/main/asciidoc/configsources.asciidoc#custom-configsources[custom ConfigSource].

Vendors implementing the MP OpenAPI specification can optionally provide additional native
ways for these configuration values to be injected into the framework
(e.g. via a server configuration file), as long as they also implement the MP Config
specification.

=== List of configurable items

Vendors must support all the <<Core configurations>> of this specification.
Optionally, they may also support <<Vendor extensions>> that allow the configuration of
framework-specific values for configurations that affect implementation behavior.

For convenience of vendors (and application developers using custom ConfigSources),
the full list of supported configuration keys is available as constants in the
https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASConfig.java[OASConfig] class.

==== Core configurations

The following is a list of configuration values that every vendor must support.

[cols="1,4"]
|===
| Config key | Value description

| `mp.openapi.model.reader` | Configuration property to specify the fully qualified name of the <<OASModelReader>> implementation.
| `mp.openapi.filter` | Configuration property to specify the fully qualified name of the <<OASFilter>> implementation.
| `mp.openapi.scan.disable`  |  Configuration property to disable annotation scanning. Default value is `false`.
| `mp.openapi.scan.packages`  |  Configuration property to specify the list of packages to scan. For example,
`mp.openapi.scan.packages=com.xyz.PackageA,com.xyz.PackageB`
| `mp.openapi.scan.classes`  |  Configuration property to specify the list of classes to scan. For example,
`mp.openapi.scan.classes=com.xyz.MyClassA,com.xyz.MyClassB`
| `mp.openapi.scan.exclude.packages`  |  Configuration property to specify the list of packages to exclude from scans. For example,
`mp.openapi.scan.exclude.packages=com.xyz.PackageC,com.xyz.PackageD`
| `mp.openapi.scan.exclude.classes`  |  Configuration property to specify the list of classes to exclude from scans. For example,
`mp.openapi.scan.exclude.classes=com.xyz.MyClassC,com.xyz.MyClassD`
| `mp.openapi.servers`  |  Configuration property to specify the list of global servers that provide connectivity information. For example,
`mp.openapi.servers=https://xyz.com/v1,https://abc.com/v1`
| `mp.openapi.servers.path.`   |  Prefix of the configuration property to specify an alternative list of servers to service all operations in a path. For example,
`mp.openapi.servers.path./airlines/bookings/{id}=https://xyz.io/v1`
| `mp.openapi.servers.operation.` | Prefix of the configuration property to specify an alternative list of servers to service an operation.
Operations that want to specify an alternative list of servers must define an `operationId`, a unique string used to identify the operation. For example,
`mp.openapi.servers.operation.getBooking=https://abc.io/v1`
|===

==== Vendor extensions

Vendors that wish to provide vendor-specific configuration via MP Config (instead
of another native configuration framework) must use the prefix `mp.openapi.extensions`.

== Documentation Mechanisms

There are many different ways to provide input for the generation of the resulting
OpenAPI document.

The MP OpenAPI specification requires vendors to produce a valid OpenAPI document
from pure JAX-RS 2.0 applications.  This means that vendors must process all the
relevant JAX-RS annotations (such as `@Path` and `@Consumes`) as well as Java objects
(POJOs) used as input or output to JAX-RS operations.  This is a good place to
start for application developers that are new to OpenAPI: just deploy your existing
JAX-RS application into a MP OpenAPI vendor and check out the output from `/openapi`!

The application developer then has a few choices:

1.  Augment those JAX-RS annotations with the
OpenAPI <<Annotations>>.  Using annotations means
developers don't have to re-write the portions of the OpenAPI document that are
already covered by the JAX-RS framework (e.g. the HTTP method of an operation).

2. Take the initial output from `/openapi` as a starting point to document
your APIs via <<Static OpenAPI files>>.  It's worth mentioning that these static
files can also be written before any code, which is an approach often adopted by
enterprises that want to lock-in the contract of the API.  In this case, we refer
to the OpenAPI document as the "source of truth", by which the client and provider
must abide.

3. Use the <<Programming model>> to provide a bootstrap (or complete)
OpenAPI model tree.

Additionally, a <<Filter>> is described which can update the OpenAPI model after it has
been built from the previously described documentation mechanisms.

=== Annotations

Many of these OpenAPI v3 annotations were derived from the https://github.com/swagger-api/swagger-core[Swagger Core] library, which
allows for a mostly-mechanical transformation of applications that are using that
library and wish to take advantage to the official MP OpenAPI interfaces.

==== Quick overview of annotations

The following annotations are found in the https://github.com/eclipse/microprofile-open-api/tree/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations[org.eclipse.microprofile.openapi.annotations] package.

[cols="1,4"]
|===
| Annotation | Description

| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callback.java[@Callback] | Represents a callback URL that will be invoked.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/Callbacks.java[@Callbacks] | Represents an array of Callback URLs that can be invoked.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/callbacks/CallbackOperation.java[@CallbackOperation] | Represents an operation that will be invoked during the callback.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/Components.java[@Components] | A container that holds various reusable objects for different aspects of the OpenAPI Specification.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/Explode.java[@Explode] | Enumeration used to define the value of the `explode` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/ParameterIn.java[@ParameterIn] | Enumeration representing the parameter's `in` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/ParameterStyle.java[@ParameterStyle] | Enumeration for the parameter's `style` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/SecuritySchemeIn.java[@SecuritySchemeIn] | Enumeration for the security scheme's `in` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/enums/SecuritySchemeType.java[@SecuritySchemeType] | Enumeration for the security scheme's `type` property.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/extensions/Extension.java[@Extension] | Adds an extension with contained properties.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/extension/Extensions.java[@Extensions] | Adds custom properties to an extension.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/ExternalDocumentation.java[@ExternalDocumentation] | References an external resource for extended documentation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/headers/Header.java[@Header] | Describes a single header object.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/Contact.java[@Contact] | Contact information for the exposed API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/Info.java[@Info] | This annotation encapsulates metadata about the API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/info/License.java[@License] | License information for the exposed API.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/Link.java[@Link] | Represents a design-time link for a response.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/links/LinkParameter.java[@LinkParameter] | Represents a parameter to pass to the linked operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Content.java[@Content] | Provides schema and examples for a particular media type.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DiscriminatorMapping.java[@DiscriminatorMapping] | Used to differentiate between other schemas which may satisfy the payload description.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Encoding.java[@Encoding] | Single encoding definition to be applied to single Schema Object.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/ExampleObject.java[@ExampleObject] | Illustrates an example of a particular content.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/Schema.java[@Schema] | Allows the definition of input and output data types.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/OpenAPIDefinition.java[@OpenAPIDefinition] | General metadata for an OpenAPI definition.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/Operation.java[@Operation] | Describes an operation or typically a HTTP method against a specific path.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameter.java[@Parameter] | Describes a single operation parameter.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/Parameters.java[@Parameters] | Encapsulates input parameters.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/parameters/RequestBody.java[@RequestBody] | Describes a single request body.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/response/APIResponse.java[@APIResponse] | Describes a single response from an API operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/response/APIResponses.java[@APIResponses] | A container for multiple responses from an API operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthFlow.java[@OAuthFlow] | Configuration details for a supported OAuth Flow.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthFlows.java[@OAuthFlows] | Allows configuration of the supported OAuth Flows.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/OAuthScope.java[@OAuthScope] | Represents an OAuth scope.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirement.java[@SecurityRequirement] |  Specifies a security requirement for an operation.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirements.java[@SecurityRequirements] | Represents an array of security requirements where only one needs to be satisfied.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityRequirementsSet.java[@SecurityRequirementsSet] | Represents an array of security requirements that need to be satisfied.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecurityScheme.java[@SecurityScheme] |  Defines a security scheme that can be used by the operations.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/security/SecuritySchemes.java[@SecuritySchemes] | Represents an array of security schemes that can be specified.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/Server.java[@Server]|  Represents a server used in an operation or used by all operations in an OpenAPI document.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/Servers.java[@Servers] | A container for multiple server definitions.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/servers/ServerVariable.java[@ServerVariable] | Represents a server variable for server URL template substitution.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tag.java[@Tag] | Represents a tag for the API endpoint.
| https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/annotations/tags/Tags.java[@Tags] | A container of multiple tags.
|===

==== Detailed usage of key annotations

===== Operation

.Sample 1 - Simple operation description
[source,Java]
----
@GET
@Path("/findByStatus")
@Operation(summary = "Finds Pets by status",
           description = "Multiple status values can be provided with comma separated strings")
public Response findPetsByStatus(...) { ... }
----

.Output for Sample 1
[source, yaml]
----
/pet/findByStatus:
  get:
    summary: Finds Pets by status
    description: Multiple status values can be provided with comma separated strings
    operationId: findPetsByStatus
----

.Sample 2 - Operation with different responses
[source,Java]
----
@GET
@Path("/{username}")
@Operation(summary = "Get user by user name")
@APIResponse(description = "The user",
             content = @Content(mediaType = "application/json",
                                schema = @Schema(implementation = User.class))),
@APIResponse(responseCode = "400", description = "User not found")
public Response getUserByName(
        @Parameter(description = "The name that needs to be fetched. Use user1 for testing. ", required = true) @PathParam("username") String username)
 {...}
----

.Output for Sample 2
[source, yaml]
----
/user/{username}:
    get:
      summary: Get user by user name
      operationId: getUserByName
      parameters:
      - name: username
        in: path
        description: 'The name that needs to be fetched. Use user1 for testing. '
        required: true
        schema:
          type: string
      responses:
        default:
          description: The user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        400:
          description: User not found
----

===== RequestBody

.Sample 1 - Simple RequestBody
[source,Java]
----
@POST
@Path("/user")
@Operation(summary = "Create user",
           description = "This can only be done by the logged in user.")
public Response methodWithRequestBody(
          @RequestBody(description = "Created user object", required = true,
                       content = @Content(schema = @Schema(implementation = User.class))) User user,
          @QueryParam("name") String name, @QueryParam("code") String code)
          { ... }
----

.Output for Sample 1
[source, yaml]
----
post:
    summary: Create user
      description: This can only be done by the logged in user.
      operationId: methodWithRequestBody
    parameters:
    - name: name
      in: query
      schema:
      type: string
    - name: code
      in: query
      schema:
      type: string
    requestBody:
      description: Created user object
      content:
       '*/*':
        schema:
          $ref: '#/components/schemas/User'
          required: true
    responses:
      default:
        description: no description
----

===== Servers

.Sample 1 - Extended Server scenarios
[source,Java]
----
@OpenAPIDefinition(
    servers = {
        @Server(
            description = "definition server 1",
            url = "http://{var1}.definition1/{var2}",
            variables = {
                @ServerVariable(name = "var1",
                                description = "var 1",
                                defaultValue = "1",
                                enumeration = {"1", "2"}),
                @ServerVariable(name = "var2",
                                description = "var 2",
                                defaultValue = "1",
                                enumeration = {"1", "2"})})})
@Server(
    description = "class server 1",
    url = "http://{var1}.class1/{var2}",
    variables = {
            @ServerVariable(
                      name = "var1",
                      description = "var 1",
                      defaultValue = "1",
                      enumeration = {"1", "2"}),
            @ServerVariable(
                      name = "var2",
                      description = "var 2",
                      defaultValue = "1",
                      enumeration = {"1", "2"})})
@Server(
    description = "class server 2",
    url = "http://{var1}.class2",
    variables = {
            @ServerVariable(
                       name = "var1",
                       description = "var 1",
                       defaultValue = "1",
                       enumeration = {"1", "2"})})
public class ServersResource {

    @GET
    @Path("/")
    @Server(
        description = "method server 1",
        url = "http://{var1}.method1",
        variables = {
            @ServerVariable(
                      name = "var1",
                      description = "var 1",
                      defaultValue = "1",
                      enumeration = {"1", "2"})})
    @Server(
        description = "method server 2",
        url = "http://method2"
    )
    public Response getServers() {
        return Response.ok().entity("ok").build();
    }
}
----

.Output for Sample 1
[source, yaml]
----
openapi: 3.0.0
servers:
- url: http://{var1}.definition1/{var2}
  description: definition server 1
  variables:
    var1:
      description: var 1
      enum:
      - "1"
      - "2"
      default: "1"
    var2:
      description: var 2
      enum:
      - "1"
      - "2"
      default: "1"
paths:
  /:
    get:
      operationId: getServers
      responses:
        default:
          description: default response
      servers:
      - url: http://{var1}.class1/{var2}
        description: class server 1
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
          var2:
            description: var 2
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://{var1}.class2
        description: class server 2
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://{var1}.method1
        description: method server 1
        variables:
          var1:
            description: var 1
            enum:
            - "1"
            - "2"
            default: "1"
      - url: http://method2
        description: method server 2
        variables: {}
----

===== Schema

.Sample 1 - Schema POJO
[source,Java]
----
@Schema(name="MyBooking", description="POJO that represents a booking.")
public class Booking {
    @Schema(required = true, example = "32126319")
    private String airMiles;

    @Schema(required = true, example = "window")
    private String seatPreference;
}
----

.Output for Sample 1
[source, yaml]
----
components:
  schemas:
    MyBooking:
      description: POJO that represents a booking.
      required:
      - airMiles
      - seatPreference
      type: object
      properties:
        airMiles:
          type: string
          example: "32126319"
        seatPreference:
          type: string
          example: window
----

.Sample 2 - Schema POJO reference
[source,Java]
----
@POST
public Response createBooking(
     @RequestBody(description = "Create a new booking.",
                  content = @Content(mediaType = "application/json",
                                     schema = @Schema(implementation = Booking.class))) Booking booking) {
----

.Output for Sample 2
[source, yaml]
----
post:
  operationId: createBooking
  requestBody:
    description: Create a new booking with the provided information.
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/MyBooking'
----

For more samples please see the https://github.com/eclipse/microprofile-open-api/wiki[MicroProfile Wiki].

=== Static OpenAPI files

Application developers may wish to include a pre-generated OpenAPI document that
was written separately from the code (e.g. with an editor such as https://editor.swagger.io/[this]).

Depending on the scenario, the document may be fully complete or partially complete.
If a document is fully complete then the application developer will want to set the
`mp.openapi.scan.disable` configuration property to `true`.  If a document is partially
complete, then the application developer will need to augment the OpenAPI snippet
with annotations, programming model, or via the filter.

==== Location and formats

Vendors are required to fetch a single document named `openapi` with an extension
of `yml`, `yaml` or `json`, inside the application's `META-INF` folder.  If there
is more than one document found that matches one of these extensions the behavior
of which file is chosen is undefined (i.e. each vendor may implement their own logic),
which means that application developers should only place a single `openapi` document
into that folder.

=== Programming model

Application developers are able to provide OpenAPI elements via Java POJOs. The
complete set of models are found in the https://github.com/eclipse/microprofile-open-api/tree/master/api/src/main/java/org/eclipse/microprofile/openapi/models[org.eclipse.microprofile.openapi.models] package.

==== OASFactory

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASFactory.java[OASFactory] is used to create all of the elements of an OpenAPI tree.

For example, the following snippet creates a simple https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/models/info/Info.java[Info] element that contains a title, description, and version.

[source,java]
----
OASFactory.createObject(Info.class).title("Airlines").description("Airlines APIs").version("1.0.0");
----

==== OASModelReader

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASModelReader.java[OASModelReader] interface allows application developers to bootstrap the OpenAPI model tree
used by the processing framework.  To use it, simply create an implementation of
this interface and register it using the `mp.openapi.model.reader` configuration
key, where the value is the fully qualified name of the reader class.

.Sample META-INF/microprofile-config.properties
[code,property]
----
mp.openapi.model.reader=com.mypackage.MyModelReader
----

Similar to static files, the model reader can be used to provide either complete
or partial model trees. If providing a complete OpenAPI model tree, application
developers should set the `mp.openapi.scan.disable` configuration to `true`.
Oherwise this partial model will be used as the base model during the processing
of the other <<Documentation Mechanisms>>.

Vendors are required to call the OASReader a single time, in the order defined by
the <<Processing rules>> section.  Only a single OASReader instance is allowed per
application.

=== Filter

There are many scenarios where application developers may wish to update or remove
certain elements and fields of the OpenAPI document.  This is done via a filter,
which is called once after all other documentation mechanisms have completed.

==== OASFilter

The https://github.com/eclipse/microprofile-open-api/blob/master/api/src/main/java/org/eclipse/microprofile/openapi/OASFilter.java[OASFilter] interface allows application developers
to receive callbacks for various key OpenAPI elements.  The interface has a default
implementation for every method, which allows application developers to only override
the methods they care about.  To use it, simply create an implementation of
this interface and register it using the `mp.openapi.filter` configuration
key, where the value is the fully qualified name of the filter class.

.Sample META-INF/microprofile-config.properties
[code,property]
----
mp.openapi.filter=com.mypackage.MyFilter
----

Vendors are required to call all registered filters in the application (0..N) once
for each filtered element.  For example, the method `filterPathItem` is
called *for each* corresponding `PathItem` element in the model tree.  This allows
application developers to filter the element and any of its descendants.

The order of filter methods called is undefined, with two exceptions:

1.  All filterable descendant elements of a filtered element must be called before its ancestor.
2.  The `filterOpenAPI` method must be the *last* method called on a filter (which
is just a specialization of the first exception).

=== Processing rules

The processed document available from the <<OpenAPI Endpoint>> is built from a variety of sources,
which were outlined in the sub-headings of <<Documentation Mechanisms>>.  Vendors
are required to process these different sources in the following order:

1. Fetch configuration values from `mp.openapi` namespace
2. Call OASModelReader
3. Fetch static OpenAPI file
4. Process annotations
5. Filter model via OASFilter

**Example processing**:

* A vendor starts by fetching all available <<Configuration>>.  If
an `OASModelReader` was specified in that configuration list, its `buildModel`
method is called to form the starting OpenAPI model tree for this application.
* Any <<Vendor specific configuration>> are added on top of that starting model (overriding
conflicts), or create a new model if an `OASModelReader` was not registered.
* The vendor searches for a file as defined in the section <<Static OpenAPI files>>.
If found, it will read that document and merge with the model produced by previous
processing steps (if any), where conflicting elements from the static file will override
the values from the original model.
* If annotation scanning was not disabled, the JAX-RS and OpenAPI annotations from
the application will be processed, further overriding any conflicting elements
from the current model.
* The final model is filtered by walking the model tree and invoking all registered
<<OASFilter>> classes.

== OpenAPI Endpoint

=== Overview
A fully processed and valid OpenAPI document must be available at the root
URL `/openapi`, as a `HTTP GET` operation.

For example, `GET http://myHost:myPort/openapi`.

This document represents the result of the applied <<Processing rules>>.

The protocol required is `http`.  Vendors are encouraged, but not required, to
support the `https` protocol as well, to enable a secure connection to the OpenAPI
endpoint.

=== Content format
The default format of the `/openapi` endpoint is `YAML`.

Vendors must also support the `JSON` format if the request contains an `Accept`
header with a value of `application/json`, in which case the response must contain
a `Content-Type` header with value of `application/json`.

=== Query parameters
No query parameters are required for the `/openapi` endpoint.  However, one
suggested but optional query parameter for vendors to support is `format`,
where the value can be either `json` or `yaml`, to facilitate the toggle between
the default `yaml` format and `json` format.

=== Context root behaviour
Vendors are required to ensure that the combination of each global https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#serverObject[server]
element and https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#pathItemObject[pathItem] element resolve to the absolute backend URL of that
particular path.  If that `pathItem` contains a `servers` element , then this
list of operation-level `server` elements replaces the global list of servers
for that particular `pathItem`.

For example:  an application may have an `ApplicationPath` annotation with the
value of `/`, but is assigned the context root of `/myApp` during deployment. In
this case, the `server` elements (either global or operation-level) must either
end with `/myApp` or a corresponding proxy.  Alternatively it is valid, but discouraged, to
add that context root (`/myApp`) to every `pathItem` defined in that application.

=== Multiple applications

The 1.0 version of the MicroProfile OpenAPI specification does not define how
the `/openapi` endpoint may be partitioned in the event that the MicroProfile
runtime supports deployment of multiple applications. If an implementation wishes
to support multiple applications within a MicroProfile runtime, the semantics of
the `/openapi` endpoint are expected to be the logical AND of all the applications
in the runtime, which would imply merging multiple OpenAPI documents into a single
valid document (handling conflicting IDs and unique names).

== Limitations

=== Internationalization
The 1.0 version of the MicroProfile OpenAPI spec does not require vendors to
support multiple languages based on the `Accept-Language`.  One reasonable
approach is for vendors to support unique keys (instead of hardcoded text) via
the various <<Documentation Mechanisms>>, so that the implementing framework can
perform a global replacement of the keys with the language-specific text that
matches the `Accept-Language` request for the `/openapi` endpoint.  A cache of
processed languages can be kept to improve performance.

=== Validation

The MP OpenAPI 1.0 specification does not mandate vendors to validate the resulting
OpenAPI v3 model (after processing the 5 steps previously mentioned), which means
that the behavior of invalid models is vendor specific (i.e. vendors may choose to
ignore, reject, or pass-through invalid inputs).

=== Cross Origin Resource Sharing (CORS)

The MP OpenAPI 1.0 specification does not require vendors to support https://www.w3.org/TR/cors/[CORS]
for the `/openapi` endpoint.  The behavior of CORS requests is implementation dependent.

include::release_notes.asciidoc[]


Fix author list

Fix author list

[[spring-cloud-stream-reference]]
= Spring Cloud Stream Reference Guide
Sabby Anandan; Marius Bogoevici; Eric Bottard; Mark Fisher; Ilayaperumal Gopinathan; Gunnar Hillert; Mark Pollack; Patrick Peralta; Glenn Renfro; Thomas Risberg; Dave Syer; David Turanski; Janne Valkealahti; Benjamin Klein; Soby Chacko; Vinicius Carvalho
:doctype: book
:toc:
:toclevels: 4
:source-highlighter: prettify
:numbered:
:icons: font
:hide-uri-scheme:
:spring-cloud-stream-repo: snapshot
:github-tag: master
:spring-cloud-stream-docs-version: current
:spring-cloud-stream-docs: http://docs.spring.io/spring-cloud-stream/docs/{spring-cloud-stream-docs-version}/reference
:spring-cloud-stream-docs-current: http://docs.spring.io/spring-cloud-stream/docs/current-SNAPSHOT/reference/html/
:github-repo: spring-cloud/spring-cloud-stream
:github-raw: http://raw.github.com/{github-repo}/{github-tag}
:github-code: http://github.com/{github-repo}/tree/{github-tag}
:github-wiki: http://github.com/{github-repo}/wiki
:github-master-code: http://github.com/{github-repo}/tree/master
:sc-ext: java
// ======================================================================================

= Spring Cloud Stream Core
:stream-docs-basedir: ../../..
include::spring-cloud-stream-aggregate.adoc[]

= Appendices
[appendix]
include::building.adoc[]
include::contributing.adoc[]

// ======================================================================================

[[spring-cloud-stream-reference]]
= Spring Cloud Stream Reference Guide
Sabby Anandan; Marius Bogoevici; Eric Bottard; Mark Fisher; Ilayaperumal Gopinathan; Gunnar Hillert; Mark Pollack; Patrick Peralta; Glenn Renfro; Thomas Risberg; Dave Syer; David Turanski; Janne Valkealahti; Benjamin Klein
:doctype: book
:toc:
:toclevels: 4
:source-highlighter: prettify
:numbered:
:icons: font
:hide-uri-scheme:
:spring-cloud-stream-repo: snapshot
:github-tag: master
:spring-cloud-stream-docs-version: current
:spring-cloud-stream-docs: http://docs.spring.io/spring-cloud-stream/docs/{spring-cloud-stream-docs-version}/reference
:spring-cloud-stream-docs-current: http://docs.spring.io/spring-cloud-stream/docs/current-SNAPSHOT/reference/html/
:github-repo: spring-cloud/spring-cloud-stream
:github-raw: http://raw.github.com/{github-repo}/{github-tag}
:github-code: http://github.com/{github-repo}/tree/{github-tag}
:github-wiki: http://github.com/{github-repo}/wiki
:github-master-code: http://github.com/{github-repo}/tree/master
:sc-ext: java
// ======================================================================================

= Spring Cloud Stream Core
:stream-docs-basedir: ../../..
include::spring-cloud-stream-aggregate.adoc[]

= Appendices
[appendix]
include::building.adoc[]
include::contributing.adoc[]

// ======================================================================================