Contents

Overview

The OpenAPI specification provides a standard way to express RESTful APIs.

Separately, the OpenAPI generator project has created a powerful code generator tool which accepts an OpenAPI document and generates client and server code for many languages and frameworks. The Helidon team contributes to this tool to ensure that it provides strong support for Helidon SE clients and servers. As a result, you can use the generator to create code that fits smoothly into your Helidon applications. The OpenAPI generator release 6.2.1 gained particularly strong support for Helidon. This document applies to that release and later ones.

In the vocabulary of the tool, there are two generators for Helidon:

  • java-helidon-client (hereafter the Helidon client generator)

  • java-helidon-server (hereafter the Helidon server generator).

Each of these generators supports two libraries:

  • mp - for Helidon MP code generation

  • se - for Helidon SE code generation

Use the Helidon client generator and its se library to create a Helidon SE client based on Helidon WebClients. The resulting client library works with any server that implements the API declared in the OpenAPI document you specified when you ran the generator. The client library provides an abstraction similar to remote procedure calls (RPC). To access a remote service that implements the endpoints declared in the OpenAPI document, your code uses the generated client library first to establish a connection to the remote service and then to call remote service endpoints by invoking local methods passing POJO business objects or Java types as arguments.

Use the tool’s Helidon server generator and its se library to create server endpoint stubs for a Helidon SE service. You build on these stubs by extending a generated class or implementing a generated interface, adding your specific business logic to finish the implementation of the endpoints. The combination of the generated server code plus Helidon SE underneath it allows you to focus on the business details instead of resource boilerplate.

You can run the OpenAPI generators in three ways:

  • using the OpenAPI generator CLI

  • using the OpenAPI generator Maven plug-in

  • using the online OpenAPI generator website

The rest of this document walks you through how to use each technique and how to configure the generators to produce the code you want.

Maven Coordinates

Your project does not need any dependencies on the OpenAPI generator.

To use the OpenAPI generator plug-in to generate or regenerate files during your project build, add the following to your project’s pom.xml file to declare the plug-in. Choose whichever version of the generator plug-in meets your needs as long as it is at least 6.2.1.

Declaring the OpenAPI Generator Plug-in
<properties>
    <openapi-generator-version>6.2.1</openapi-generator-version>
</properties>
...
<build>
    ...
    <plugin-management>
        ...
        <plugin>
             <groupId>org.openapitools</groupId>
             <artifactId>openapi-generator-maven-plugin</artifactId>
             <version>${openapi-generator-version}</version>
        </plugin>
        ...
    </plugin-management>
    ...
</build>
Copied

A later section describes how to invoke the plug-in during your build.

Configuration

The OpenAPI generators support a substantial, powerful, and sometimes bewildering group of configuration settings. For complete lists see these pages:

The OpenAPI generator loosely divides its settings into three types:

  • global properties

    These settings generally govern the overall behavior of the tool, regardless of which specific generator you use.

    For the CLI, use the common option style:

    -i petstore.yaml

    --input-spec petstore.yaml

    For the Maven plug-in, use elements within the <configuration> section of the plug-in:

    <configuration>
        <inputSpec>petstore.yaml</inputSpec>
    </configuration>
    Copied
  • options

    These settings typically affect how particular generators operate.

    For the CLI, specify config options as additional properties:

    --additional-properties=groupId=com.mycompany.test,artifactId=my-example

    or

    -p groupId=com.mycompany.test
    -p artifactId=my-example
    Copied

    For the Maven plug-in, use the <configOptions> section within <configuration>:

    <configuration>
        ...
        <configOptions>
            <groupId>com.mycompany.test</groupId>
            <artifactId>my-example</artifactId>
        </configOptions>
        ...
    </configuration>
    Copied
  • additional properties

    Settings in this category typically are passed to the templates used in generating the files, although generators can use additional properties in deciding how to generate the files.

    For the CLI:

    --additional-properties "useAbstractClasses=false,returnResponse=true"

    or

    -p useAbstractClasses=false
    -p returnResponse=true
    Copied

    For the Maven plug-in, use an <additionalProperties> section within the <configuration> section for the plug-in:

    <configuration>
        ....
        <additionalProperties>
            <additionalProperty>useAbstractClasses=false</additionalProperty>
            <additionalProperty>returnResponse=true</additionalProperty>
        </additionalProperties>
    </configuration>
    Copied

Keep this distinction among global options, config options, and additional properties in mind so you know how to express the configuration you want. The earlier links to the lists of configuration options for the Helidon generators groups options and additional properties in separate tables.

The next few sections describe, in turn, required settings, settings we recommend, and other common settings most developers will want to use.

Required Settings

You must specify the following options:

Required OpenAPI Generator Options
OptionShort OptionPlug-in SettingDescriptionValues
--inputSpec-i<inputSpec>Path to the OpenAPI document defining the REST API
--generatorName-g<generatorName>Generator you want to use (java-helidon-server or java-helidon-client)java-helidon-server
java-helidon-client

Your project might have different needs, but in general we advise developers to use the following settings when using the OpenAPI generator.

Recommended OpenAPI Generator Additional Properties
PropertyDescriptionDefault
apiPackageName of the package for generated API interfaces/classesorg.openapitools.server.api or
org.openapitools.client.api
modelPackageName of the package for generated model (POJO) classesorg.openapitools.server.model or
org.openapitools.client.model
invokerPackageName of the package for generated driver classesorg.openapitools.server or
org.openapitools.client
groupIdGroup ID in the generated pom.xmlorg.openapitools
artifactIdArtifact ID in the generated pom.xmlopenapi-java-server or
openapi-java-client
artifactVersionArtifact version in the generated pom.xml1.0.0

Note

The next table contains recommendations only for using the OpenAPI generator plug-in (not for using the CLI).

Recommended OpenAPI Generator Plug-in Options
Plug-in OptionDescriptionDefault
<output>Directory where the generator should place files.
+ We strongly recommend <output>target/generated-sources</output> or a subdirectory below there.
.
(current directory)
<addCompileSourceRoot>Whether Maven should include the output directory as a source root (that is, include it automatically in the build).
+ We advise <addCompileSourceRoot>true</addCompileSourceRoot>.
false

Common Settings

Among the many configuration settings available to you, some you should particularly consider are summarized in the table below. Refer to the earlier links for complete lists.

Common OpenAPI Generator Additional Properties
PropertyDescriptionValuesDefaultNotes
helidonVersionVersion of Helidon for which to generate the files 2.5.2

Affects:

  • Helidon version for the <parent>

  • Dependencies (javax vs. jakarta)

  • java import statements in generated code (javax vs. jakarta)

fullProjectWhether to generate all the normal files or only API filestrue/falsefalseThe "API files" include files developers do not normally modify after they are generated: the interfaces or classes for the declared API and the model classes.
serializationLibrarywhich Java library to use for serializing JSONjsonb, jacksonjackson

Usage

This section covers two major topics:

Planning Your Use of the OpenAPI Generators

Beyond the settings listed above, there are several important choices you need to make when planning your project and when running the OpenAPI generators. This section addresses those choices.

Generating a New Project and Generating Into an Existing Project

You can use the OpenAPI generator to create a new project or to generate files into an existing project. Some developers do both, using the generator to create the project at first and then to update the project as they evolve the OpenAPI document or change the generation options they select. Others create the project in some other way—​for example, using the Helidon CLI. The OpenAPI generator CLI and plug-in both support each type of usage.

If the OpenAPI generator finds a pre-existing API or model file, it overwrites it with the latest content. It does not overwrite a pom.xml file or test files. This is important because certain generation settings can influence the generated dependencies in the pom.xml file. For example, the serializationLibrary setting creates dependencies on either JSON-B or Jackson artifacts. As a result, changing the generation options can change the dependencies your project should have. If you rerun the generator, the old pom.xml remains and does not reflect the revised depencencies.

As a practical matter, many developers use the OpenAPI generators in one of the following ways:

  • Use the generator CLI once to create a new project.

    By default, the generator CLI creates files in the normal Maven project structure: src/main/java, etc. Then you add your own files to that same project structure. Because the generated files are in the standard places, the project build includes them by default.

    Note

    You can run the generator CLI again to update the generated files. Because this happens outside the project’s build lifecycle, you need to remember to rerun the CLI yourself when you change the OpenAPI document.

    You also need to identify and manually remove any previously-generated files that become obsolete. Similarly, you must understand how changes in the OpenAPI document or the generation options affect the project dependencies and update the project pom.xml accordingly.

  • Use the generator plug-in to (re)generate files during each build.

    Specify in the plug-in configuration that the generated files should reside in target/generated-sources directory (the conventional location for generated sources) or a subdirectory below there. Each project build runs the OpenAPI generator which reads the then-current OpenAPI document file. With the generated files under target, you can use mvn clean to remove any obsolete generated files left over from previous builds.

    Note

    In particular, with mvn clean each build regenerates the candidate pom.xml under target/generated-sources. You can inspect the generated pom.xml file for changes in dependencies and make any necessary changes in the actual project pom.xml file.

Generating Interfaces or Classes

As you generate a Helidon SE server, you can choose whether you want Java interfaces or classes to represent the RESTful API endpoints.

By default, the Helidon OpenAPI server generator creates classes. You write your own concrete subclasses which extend those generated classes, supplying the business logic for each REST endpoint. Do not modify the generated classes.

If you set useAbstractClasses=false then the generator creates Java interfaces instead of classes. You then write classes which implement those generated interfaces.

Either way, you can safely regenerate the code later so long as you have not edited the generated code. The generator replaces the generated classes or interfaces but does not touch other classes you wrote.

The Helidon client generator always creates concrete classes. Typically, you do not need to customize the behavior in the generated client API classes. If you choose to do so, write your own subclass of the generated client API class; do not modify the generated files.

Grouping Operations into "APIs"

Each operation in an OpenAPI document can have a tags attribute. The generators group operations with the same tags value into the same API.

When you generate a Helidon SE server, the generator creates a separate interface or class for each API your service exposes. You implement each interface or extend each class to add your business logic for that API.

When you generate a Helidon SE client, the generated code contains a separate API class for each distinct API your code might invoke.

Running the OpenAPI Generators

Earlier we listed the ways you can run the OpenAPI generator:

  • using the OpenAPI generator CLI

  • using the OpenAPI generator Maven plug-in

  • using the online OpenAPI generator website

The next sections describe each of these techniques in detail.

Using the OpenAPI Generator CLI

Downloading the OpenAPI Generator CLI

You need to download the CLI .jar file before you can run the CLI. Follow these instructions and remember where you save the .jar file. The examples below use the placeholder path-to-generator to represent the directory where you store that downloaded file.

The following example uses the Helidon server generator to create a project or regenerate files into an existing project.

Creating or updating a server project using the OpenAPI generator CLI
java -jar ${path-to-generator}/openapi-generator-cli.jar \
  generate \
  -i src/main/resources/petstore.yaml \
  -g java-helidon-server \
  --library se \
  -p groupId=io.helidon.examples \
  -p artifactId=helidon-openapigen-se-server \
  -p artifactVersion=1.0.0-SNAPSHOT \
  -p apiPackage=io.helidon.examples.openapigen.se.server.api \
  -p modelPackage=io.helidon.examples.openapigen.se.server.model \
  -p invokerPackage=io.helidon.examples.openapigen.se.server
Copied

The next example runs the Helidon client generator using the same input file.

Creating or updating a client project using the OpenAPI generator CLI
java -jar ${path-to-generator}/openapi-generator-cli.jar \
  generate \
  -i src/main/resources/petstore.yaml \
  -g java-helidon-client \
  --library se \
  -p groupId=io.helidon.examples \
  -p artifactId=helidon-openapigen-se-client \
  -p artifactVersion=1.0.0-SNAPSHOT \
  -p apiPackage=io.helidon.examples.openapigen.se.client.api \
  -p modelPackage=io.helidon.examples.openapigen.se.client.model \
  -p invokerPackage=io.helidon.examples.openapigen.se.client
Copied

The key differences between the commands are:

  • the generator selected by the -g option (client vs. server),

  • the artifact ID and package names (client vs. server).

You could use these two commands together to generate a server submodule and a client submodule in a pre-existing multi-module Maven project. Remember that the resulting client project can access any server which implements the API described in the petstore.yaml OpenAPI document, whether it was generated using the OpenAPI generator tool or not.

In both examples, the generator creates the entire project if it does not exist and recreates the generated API and model files if the project already exists. The generator does not overwrite an existing pom.xml file, previously-generated test files, or files you create yourself.

Invoking the OpenAPI Generator Maven Plug-in

You can run the OpenAPI generator plug-in as part of your project build to generate or regenerate files.

First, declare the plug-in as explained in the earlier section on Maven coordinates.

Then, in the <build> section of your pom.xml file, add an execution of the plug-in with the configuration you want. By default, the plug-in runs during the generate-sources phase of the Maven build.

The plug-in execution in the following example is equivalent to the CLI example above for generating server files:

Creating or updating a client project using the OpenAPI Maven plug-in
<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <inputSpec>${project.basedir}/src/main/resources/petstore.yaml</inputSpec>
                <generatorName>java-helidon-client</generatorName>
                <library>se</library>
                <output>${project.build.directory}/generated-sources/client</output> 
                <addCompileSourceRoot>true</addCompileSourceRoot>
                <configOptions>
                    <groupId>io.helidon.examples</groupId>
                    <artifactId>helidon-openapigen-se-client</artifactId>
                    <artifactVersion>1.0.0-SNAPSHOT</artifactVersion>
                    <apiPackage>io.helidon.examples.openapigen.se.client.api</apiPackage>
                    <modelPackage>io.helidon.examples.openapigen.se.client.model</modelPackage>
                    <invokerPackage>io.helidon.examples.openapigen.se.client</invokerPackage>
                </configOptions>
                <additionalProperties>
                    <additionalProperty>returnResponse=true</additionalProperty>
                </additionalProperties>
            </configuration>
        </execution>
    </executions>
</plugin>
Copied
  • Specifies that the generated files should reside in the target/generated-sources/client directory.

Using the Online Generator

The OpenAPI tools project hosts and maintains the online OpenAPI generator at http://api.openapi-generator.tech. You can use the site’s API browser to explore the available generators and the settings each supports, expressed as JSON.

To generate your project, you supply the options and additional properties as JSON. The online generator provides you with a file ID, and you refer to the file ID in a subsequent HTTP request to retrieve your project.

Note

The online generator stores your project on the server which you then retrieve using a separate HTTP request. Before you use the online generator, consider whether any of the input you provide—​the OpenAPI document, package or Maven coordinates—​and therefore the generated project will reveal any sensitive information.

This document does not explore further the use of the online generator.

Using the Generated Code

The Helidon generators go a long way in helping you write your client or server. Even so, there are important parts of your project only you can provide. This section describes your next steps after you have run the generator.

Completing the Server

Recall from earlier how the OpenAPI generator gathers operations into one or more "APIs" and generates either a class or an interface—​your choice—​for each API. You need to extend each generated API class or implement each generated API interface by writing your own classes. Any input parameters to the endpoints are expressed as POJO model objects or Java types, as declared in the OpenAPI document. Your server code uses each of the input parameters to accomplish whatever business purpose that endpoint is responsible for, possibly returning a result as a POJO or Java type as indicated for that operation in the OpenAPI document.

The Helidon SE server generator also creates, for each API, a separate class containing handler methods for each endpoint. Along with the PetService interface or abstract class which has methods such as addPet and getPetById, the tool generates PetServiceImpl with methods such as handleAddPet and handleGetPetById.

Generated PetService abstract class
public abstract class PetService implements Service {
    void addPet(ServerRequest request, ServerResponse response, Pet pet) {
        // ...
    }
    abstract void handleAddPet(ServerRequest request, ServerResponse response, Pet pet);

    void getPetById(ServerRequest request, ServerResponse response) {
        // ...
    }
    abstract void handleGetPetById(ServerRequest request, ServerResponse response, Long petId);
}
Copied
Generated skeleton PetServiceImpl class (which you extend)
public class PetServiceImpl extends PetService {
    public void handleAddPet(ServerRequest request, ServerResponse response, Pet pet) {
        response.status(HTTP_CODE_NOT_IMPLEMENTED.send());
    }

    public void handleGetPetById(ServerRequest request, ServerResponse response, Long petId) {
        response.status(HTTP_CODE_NOT_IMPLEMENTED).send();
    }
}
Copied

You write your own classes which extend PetServiceImpl and the other generated xxxImpl classes, overriding the handle…​ methods.

You have control over—​and therefore responsibility for—​preparing the response to be sent to the client, including the status, any response headers, and any returned entity. Your overriding implementation of handleGetPetById might look like the following example.

Example override of handleGetPetById
public void handleGetPetById(ServerRequest request, ServerResponse response, Long petId) {
    Pet pet = locatePetInDatabase(petId);
    if (pet == null) {
        response.status(404).send();
    }
    response.send(pet); // Respnose status is 200 by default.
    }
}
Copied

Using the Client Library

The generated client code represents a true library. Typically, you do not need to customize the generated client code itself. You do need to write code to invoke the code in that library.

The generated Helidon SE client includes the class ApiClient. This class corresponds to the Helidon WebClient and represents the connection between your code and the remote server. The generator also creates one or more Api interfaces and corresponding implementation classes. The examples below use the PetApi interface and the PetApiImpl class.

To invoke the remote service your code must:

  1. Create an instance of ApiClient using an ApiClient.Builder.
  2. Use that ApiClient instance to instantiate a PetApi object.
  3. Invoke the methods on the PetApi object to access the remote services and then retrieve the returned result value.

The following sections explain these steps.

Creating an ApiClient Instance

The Helidon SE client generator gives you as much flexibility as you need in connecting to the remote service.

Internally, the ApiClient uses a Helidon WebClient object to contact the remote system. The ApiClient.Builder automatically prepares a Helidon WebClient.Builder object using information from the OpenAPI document.

The next sections describe, from simplest to most complicated, the ways your code can create an ApiClient instance, each involving increased involvement with the WebClient.Builder object.

Accepting the Automatic WebClient.Builder

In the simplest case, your code can get an ApiClient instance directly.

Creating an ApiClient instance - simple case
ApiClient apiClient = ApiClient.builder().build();
Copied

Your code relies fully on the automatic WebClient.Builder. In many cases, this approach works very well, especially if the OpenAPI document correctly declares the servers and their URIs.

Influencing the Automatic WebClient.Builder

Your code can use the ApiClient.Builder to fine-tune the settings for the internal WebClient.Builder. For instance, your code can set an object mapper to be used for Jackson processing or the JsonbConfig object to be used for JSON-B processing, depending on which serialization library you chose when you ran the generator.

Your code does not need to know how the object mapper setting is conveyed to the internal WebClient.Builder. The ApiClient.Builder knows how to do that.

Creating an ApiClient instance - influencing the ApiClient.Builder
ApiClient apiClient = apiClient.builder()
                            .objectMapper(yourCustomMapper)
                            .build();
Copied
Adjusting the Automatic WebClient.Builder

In more complicated situations, your code can adjust the settings of the WebClient.Builder the ApiClient.Builder creates.

Creating an ApiClient instance - adjusting the WebClient.Builder
ApiClient.Builder apiClientBuilder = ApiClient.builder();

apiClientBuilder.webClientBuilder() 
                .connectTimeout(4, TimeUnit.SECONDS); 

ApiClient apiClient = apiClientBuilder.build(); 
Copied
  • Access the ApiClient.Builder’s automatic `WebClient.Builder instance.
  • Adjust a setting of the WebClient.Builder directly.
  • Build the ApiClient which implicitly builds the WebClient from the now-adjusted internal WebClient.Builder.

The automatic WebClient.Builder retains information derived from the OpenAPI document unless your code overrides those specific settings.

Providing a Custom WebClient.Builder

Lastly, you can construct the WebClient.Builder entirely yourself and have the ApiClient.Builder use it instead of its own internal builder.

Creating an ApiClient instance - using a custom WebClient.Builder
WebClient.Builder customWebClientBuilder = WebClient.builder()
                .connectTimeout(3, TimeUnit.SECONDS)
                .baseUri("https://myservice.mycompany.com");

ApiClient apiClient = ApiClient.builder()
                        .webClientBuilder(customWebClientBuilder)
                        .build();
Copied

Note that this approach entirely replaces the internal, automatically-prepared WebClient.Builder with yours; it does not merge the new builder with the internal one. In particular, any information from the OpenAPI document the generator used to prepare the internal WebClient.Builder is lost.

Creating a PetApi Instance

The ApiClient represents the connection to the remote server but not the individual RESTful operations. Each generated xxxApi interface exposes a method for each operation declared in the OpenAPI document associated with that API via its tags value. By example, the PetApi interface exposes a method for each operation in the OpenAPI document that pertains to pets.

To invoke an operation defined on the PetApi interface, your code instantiates a PetApi using an ApiClient object:

Preparing the PetStore Client API
ApiClient apiClient = ApiClient.builder().build();
PetApi petApi = PetApiImpl.create(apiClient);
Copied

Invoking Remote Endpoints

With the petApi object, your code can invoke any of the methods on the PetApi interface to contact the remote service.

The Helidon WebClient follows a reactive programming model, and the Helidon SE client generator creates an ApiResponse interface, also reactive. Each generated PetApi method returns an ApiResponse<returnType> where the returnType is the return type declared in the OpenAPI document for the corresponding operation.

The ApiResponse interface exposes two methods your code can use to work with the response from the remote service invocation:

  • Single<T> result()

    Provides reactive access to the value returned by the remote service in the response. This method lets your code fetch the return value directly.

  • Single<WebClientResponse> webClientResponse()

    Provides reactive access to the Helidon WebClientResponse object. Your code can find out the HTTP return status, read headers in the response, and process the content (if any) in the response however it needs to.

In the reactive Helidon WebClient model, the first part of the response message can arrive (the status and headers are available) before the entity in the body of the response is readable. So there are two reactive events associated with an incoming HTTP response:

  1. when the response excluding the entity content has arrived, and
  2. when your code can begin consuming the entity content.

You can adopt different styles of retrieving the results, depending on the specific needs of the code you are writing.

Synchronous access to the result

This example shows the simplest way to invoke the remote service and work with the result.

Synchronous access to the return value
// Assumes the petApi field is initialized as above.
List<Pet> availablePets = petApi.findPetsByStatus(List.of(Pet.StatusEnum.AVAILABLE.value())) 
                .result() 
                .await(4, TimeUnit.SECONDS); 
Copied
  • Start the remote service invocation.
  • Access the reactive result.
  • Wait for the result to arrive subject to a four-second timeout.

This code blocks the current thread, waiting up to four seconds for the response to arrive. This approach might be adequate if you are developing a command-line client where the thread has no other meaningful work to do until it has the result. This is not an appropriate style for server code that uses the generated client to invoke another service.

Note that this approach offers no access to the HTTP status for the response or any headers that might have been returned.

Synchronous access with status checking

The Helidon WebClient programming model includes a WebClientResponse interface which exposes all aspects of the HTTP response returned from the remote service.

The next example shows how your code can use the WebClientResponse.

Synchronous access with status checking
ApiResponse<List<Pet>> apiResponse = petApi.findPetsByStatus(List.of(Pet.StatusEnum.AVAILABLE.value())); 

WebClientResponse webClientResponse = apiResponse.webClientResponse()
            .await(4, TimeUnit.SECONDS); 

if (webClientResponse.status().code() != 200) { 
    // Handle a non-successful status.
}

List<Pet>> availablePets = apiResponse.result()
            .await(4, TimeUnit.SECONDS); 
Copied
  • Start the remote service invocation.
  • Wait for the HTTP response status and headers to arrive.
  • Check the status in the HTTP response.
  • Wait for the content to arrive subject to a four-second timeout.

This code also blocks the current thread, first to wait for the initial response and then to wait for the result content.

Fully-reactive access

The following example shows how your code might invoke the remote service and process the response using the reactive programming model.

Fully-reactive access with status checking
// Assumes the petApi field is initialized as above.
ApiResponse<List<Pet>> availablePetsResponse =
    petApi.findPetsByStatus(List.of(Pet.StatusEnum.AVAILABLE.value())); 

availablePetsResponse.webClientResponse()
    .thenAccept(resp -> { 
        if (resp.status().code() == 200) {
            try {
                availablePetsResponse.result() 
                    .thenAccept(availablePets -> {
                        // Process the List<Pet> of available pets. 

                    })
                    .exceptionally(throwable -> {
                        // Handle whatever problem occurred in retrieving the results. 
                        return null;
                    });
            } catch (ExecutionException | InterruptedException e) {
                // Handle errors while waiting for the response content to arrive. 
            }
        } else {
            // Handle non-200 HTTP status. 
        })
    .exceptionally(throwable -> {
        // Handle whatever problem occurred in receiving the response. 
        return null;
    });
Copied
  • Starts the remote service invocation.
  • Reactively processes the first portion of the HTTP response.
  • Reactively processes a successfully-received HTTP response.
  • Reactively processes the successfully-returned list of available pets.
  • Reactively handles any errors in retrieving the list of available pets.
  • Handle problems that occurred while waiting for the response content to arrive.
  • Handle a non-200 response status.
  • Reactively handles any errors in receiving the HTTP response.

The fully-reactive approach brings with it some complexity, but it lets your code completely avoid blocking the thread that initiates the outbound remote service access. Avoiding blocking is especially important if the code which uses the generated client runs in a server.

Some of this complexity enters because there are several ways this processing can fail. Your code should handle each of them in whatever ways make sense for your application, and that might mean dealing with each different error scenario in a different way.

References