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

    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 in SE
:toc:
:toc-placement: preamble
:description: Helidon SE OpenAPI Support
:keywords: helidon, se, openapi
:helidon-tag: https://github.com/oracle/helidon/tree/{helidon-version}
:quickstart-example: {helidon-tag}/examples/quickstarts/helidon-quickstart-se
: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-se-openapi-example: {helidon-tag}/examples/openapi
: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 SE application to serve an OpenAPI document
that describes your application's endpoints.

== OpenAPI support in Helidon SE

You can very simply add support for OpenAPI to your Helidon SE 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
OpenAPI support in Helidon SE largely follows the 
link:{mp-openapi-spec}[MicroProfile OpenAPI spec].
But Helidon SE does not process annotations, which is one way to convey OpenAPI
information about the endpoints in your app. You can still use OpenAPI with your
Helidon SE app by providing OpenAPI information about the endpoints without
using annotations. 

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

To use OpenAPI from your Helidon SE app:

1. Edit your `pom.xml`.
2. Update your Java code to register `OpenAPISupport`.
3. Furnish OpenAPI information about your application's endpoints.
4. Update your application's Helidon configuration (optional).

=== Edit your `pom.xml`
Add a dependency for Helidon SE OpenAPI runtime support:

[source,xml,subs="attributes+"]
----
<dependency>
    <groupId>io.helidon.openapi</groupId>
    <artifactId>helidon-openapi</artifactId>
    <version>{helidon-version}</version>
</dependency>
----
This is a compile-time dependency, because your code must register
`OpenAPISupport` (a class in that artifact) like this:

=== Register `OpenAPISupport` in your Java code
[source,java]
----
Config config = Config.create();
...
return Routing.builder()
        .register(JsonSupport.create())
        .register(OpenAPISupport.create(config)) // <1>
        .register(health)                   // Health at "/health"
        .register(metrics)                  // Metrics at "/metrics"
        .register("/greet", greetService)
        .build();
----
<1> Adds the `OpenAPISupport` service to your server.  

=== Furnish OpenAPI information about your endpoints
Helidon SE 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.

==== 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 configuration to set `openapi.model.reader` as the 
fully-qualified class name of your class. Also see 
<<Add OpenAPI dependency,Add OpenAPI dependency>> below.

==== 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 `openapi.filter` as the full-qualified
class name of your class. Also see 
<<Add OpenAPI dependency,Add OpenAPI dependency>> below.

==== Add OpenAPI dependency
If you implement either a model reader or a filter, add this dependency to your 
`pom.xml`:

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

=== Update application configuration
Helidon SE support for OpenAPI supports a handful of config properties patterned after 
those described in the MicroProfile OpenAPI spec, two of which were mentioned above.

[[se_config]]
.Helidon SE OpenAPI Config Properties
|===
|Property |Use

|`openapi.model.reader` |Fully-qualified class name for the model reader
|`openapi.filter` |Fully-qualified class name for the filter
|`openapi.servers` |Lists servers that provide connectivity information
|`openapi.servers.path` |Prefix for config properties specifying alternative
servers for given paths
|`openapi.servers.operation` |Prefix for config properties specifying alternative
servers for given operations
|===
For more information on what these settings do consult the MicroProfile OpenAPI spec.

Helidon SE also supports additional properties.

.Helidon SE-specific OpenAPI Config Properties
|===
|Property |Use

|`openapi.web-context` |Path which serves the OpenAPI document (defaults to `/openapi`)
|`openapi.static-file` |Full path to the static OpenAPI file (defaults to 
 `META-INF/openapi.yml`,
 `META-INF/openapi.yaml`, or
 `META-INF/openapi.json`)
|===

Set these config properties in one of the config sources your app uses so the
Helidon config system will load them. Often developers use `application.yaml` at the 
top level of the application JAR.

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

By default, Helidon OpenAPI returns the OpenAPI document in 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.

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