///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

    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.

///////////////////////////////////////////////////////////////////////////////

= OpenAPI
:toc:
:toc-placement: preamble
:description: Helidon MP OpenAPI Support
:keywords: helidon, mp, microprofile, openapi
:helidon-tag: https://github.com/oracle/helidon/tree/{helidon-version}
:mp-openapi-prefix: https://github.com/eclipse/microprofile-open-api/blob/master
:mp-openapi-spec: {mp-openapi-prefix}/spec/src/main/asciidoc/microprofile-openapi-spec.adoc
:openapi-spec: https://github.com/OAI/OpenAPI-Specification
:helidon-mp-openapi-example: {helidon-tag}/examples/microprofile/openapi-basic
:jandex-plugin-doc: https://github.com/wildfly/jandex-maven-plugin
:model-reader-java: {mp-openapi-prefix}/api/src/main/java/org/eclipse/microprofile/openapi/OASModelReader.java
:filter-java: {mp-openapi-prefix}/api/src/main/java/org/eclipse/microprofile/openapi/OASFilter.java

Easily allow your Helidon MP application to serve an OpenAPI document
that describes your application's endpoints.

== OpenAPI support in Helidon MP

You can very simply add support for OpenAPI to your Helidon MP application. This 
document shows what changes you need to make to your application and how to access
the OpenAPI document for your application at runtime.

== Changing your application
Helidon MP conforms to the link:{mp-openapi-spec}[MicroProfile OpenAPI specification],
which was inspired by the link:{openapi-spec}[OpenAPI spec] itself.

Helidon MP includes a link:{helidon-mp-openapi-example}[complete OpenAPI example]
based on the MP quick-start sample app.

To use OpenAPI from your Helidon MP app:

1. Edit your `pom.xml`.
2. Furnish OpenAPI information about your application's endpoints.
3. Update your application's configuration (optional).

=== Edit your `pom.xml`
==== Building the Jandex index
A Jandex index stores information about the classes and methods in your app and
what annotations they have. It allows CDI to process annotations faster during your 
application's start-up.

Add the link:{jandex-plugin-doc}[Jandex maven plug-in] to the `<build><plugins>` 
section of your `pom.xml`:

[source,xml,subs="attributes+"]
----
<plugin>
    <groupId>org.jboss.jandex</groupId>
    <artifactId>jandex-maven-plugin</artifactId>
    <version>{jandex-plugin-version}</version>
    <executions>
      <execution>
        <id>make-index</id>
        <goals>
          <goal>jandex</goal>
        </goals>
      </execution>
    </executions>
</plugin>
----
When you build your app `maven` should include the index `META-INF/jandex.idx` in 
the JAR.

[NOTE]
====
If you _do not_ modify your build to create 
the index then the Helidon MP OpenAPI runtime automatically creates one in memory during 
app start-up. This slows down your app start-up and, depending on how CDI is 
configured, might inadvertently miss information. 

We _strongly recommend_ using the Jandex plug-in to build the index into your app.
====

==== Adding Helidon MP OpenAPI support to your app
Add these two sections to the `<dependencies>` portion of your `pom.xml`:

[source,xml,subs="attributes+"]
----
<dependency> <!--1-->
    <groupId>org.eclipse.microprofile.openapi</groupId>
    <artifactId>microprofile-openapi-api</artifactId>
    <version>{microprofile-openapi-version}</version>
</dependency>

<dependency> <!--2-->
    <groupId>io.helidon.microprofile.openapi</groupId>
    <artifactId>helidon-microprofile-openapi</artifactId>
    <version>{helidon-version}</version>
    <scope>runtime</scope>
</dependency>
----
<1> Defines the MicroProfile OpenAPI annotations so you can use them in your code.
<2> Adds the Helidon MP OpenAPI runtime support.

=== Furnish OpenAPI information about your endpoints
Helidon MP OpenAPI combines information from all of the following sources as it 
builds its in-memory model of your application's API. It constructs the OpenAPI
document from this internal model. Your application can use one or more of these
techniques.

==== Annotate the endpoints in your app
You can add MicroProfile OpenAPI annotations to the endpoints in your source code.
These annotations allow the Helidon MP OpenAPI runtime to discover the endpoints
and information about them via CDI at app start-up.

Here is one of the endpoints, annotated for OpenAPI, from the example mentioned earlier:

[source,java]
----
@GET
@Operation(summary = "Returns a generic greeting", // <1>
        description = "Greets the user generically")
@APIResponse(description = "Simple JSON containing the greeting", // <2>
        content = @Content(mediaType = "application/json",
                           schema = @Schema(implementation = GreetingMessage.class)))
@Produces(MediaType.APPLICATION_JSON)
public JsonObject getDefaultMessage() {...}
----
<1> `@Operation` gives information about this endpoint.
<2> `@APIResponse` describes the HTTP response and declares its media type and contents.

You can also define any request parameters the endpoint expects, although this
endpoint uses none.

This excerpt shows only a few annotations for illustration. The 
link:{helidon-mp-openapi-example}[Helidon MP OpenAPI example] illustrates more, 
and the link:{mp-openapi-spec}[MicroProfile OpenAPI spec] describes them all.

==== Provide a static OpenAPI file
Add a static file at `META-INF/openapi.yml`, `META-INF/openapi.yaml`, 
or `META-INF/openapi.json`. Tools such as Swagger let you describe your app's API
and they then generate an OpenAPI document file which you can include in your application
so OpenAPI can use it.

==== Write and configure a model reader class
Write a Java class that implements the OpenAPI 
link:{model-reader-java}[`org.eclipse.microprofile.openapi.OASModelReader`] interface. Your
model reader code programmatically adds elements to the internal model that OpenAPI
builds. 

Change your application's MP configuration to set `mp.openapi.model.reader` as the 
fully-qualified class name of your class.

==== Write and configure a filter class
Write a Java class that implements the OpenAPI 
link:{filter-java}[`org.eclipse.microprofile.openapi.OASFilter`] interface. 
As OpenAPI composes its internal model, it invokes your filter with each 
model element _before_ adding the element to the model. Your filter can 
accept the element as-is, modify it, or suppress it.

Change your application's configuration to set `mp.openapi.filter` as the full-qualified
class name of your class.

=== Update your application configuration
Beyond the two config properties that denote the model reader and filter, Helidon
MP OpenAPI supports a number of others. These are described in the 
link:{mp-openapi-spec}#configuration[configuration section] of the MicroProfile 
OpenAPI spec.

== Accessing the OpenAPI document
Now your Helidon MP application will automatially respond to an additional endpoint --
 `/openapi` -- and it will return the OpenAPI document describing the endpoints
in your application.

By default, per the MicroProfile OpenAPI spec, the default format of the OpenAPI document is YAML. 
There is not yet an adopted IANA YAML media type, but a proposed one specifically
for OpenAPI documents that has some support is `application/vnd.oai.openapi`.
That is what Helidon returns, by default.

A client can specify `Accept:` as either `application/vnd.oai.openapi+json` or `application/json`
to request JSON.
