Getting started with OpenAPI Generators : tips and tricks
Tags: java, openapi, api, development
Published: 2023-05-20 12:40:00

---
title: Getting started with OpenAPI Generators : tips and tricks
published: true
date: 2022-12-30 23:57:08 UTC
tags: java,openapi,apis,development
canonical_url: https://lengrand.fr/tips-on-getting-started-with-openapi-generators/
---

 ![Getting started with OpenAPI Generators : tips and tricks](https://images.unsplash.com/photo-1623282033815-40b05d96c903?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGFwaXxlbnwwfHx8fDE2NzIxMzM4MzM&ixlib=rb-4.0.3&q=80&w=2000)

_TL;DR : In this article, I'm sharing some tips and tricks on how to get productive with creating OpenAPI generators_

Lately, I've started dabbling more and more with [OpenAPI](https://github.com/OAI/OpenAPI-Specification). The OpenAPI specification is a super useful way to describe the API that you're exposed to your users, both internally and externally.

Some of you may also have heard about those under the name of "Swagger files". They're both kinda the same in the common speak, though OpenAPI is an open standard (lead with the OpenAPI Initiative) and Swagger is a set of tools built by a company ([SmartBear](https://smartbear.com/)). Some of those tools are Open-Source, while others have a pro license. I won't go into the details of the specification here, there are plenty of great getting started resources, typically for different technologies. [Here's one for Java and Spring](https://www.baeldung.com/spring-rest-openapi-documentation).

**Generators** are the parts who take the OpenAPI model that's being created from a definition file, and generates server / client code and / or documentation. Or anything you want, really. There's [many generators](https://openapi-generator.tech/docs/generators) available out of the box, so typically what you want is use or adapt one of them. It's not _always_ the case though. For example, there is currently no generator available for the [Jetbrains HTTP Client](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html).

That's where my story begins 😊, but that's for another day!

## Using the debugging flags

Typically, if you're playing with a generator, you either want to generate a model file (your data structure), an operation file (your logic), or a supporting file (basically anything else, READMEs, docs, ...).

At its core, the idea of OpenAPI is quite simple : It takes a specification file, transforms it into a set of objects in memory, and uses those objects to generates code / files using [mustache](http://mustache.github.io/) template files. You can read more about it [here](https://openapi-generator.tech/docs/templating).

That's why it's crucial to have a good look into those objects, so that you can find what know where the data you need is located inside your mustache template. Here, debugging flags become vital. There's 3 of them, whether you want to see the data to generate models, operations or supporting files.

You can use respectively `debugModels`, `debugOpenAPI` and /or `debugSupportingFiles`. and you set them by running the desired  `generate` command with the correct flag. For example

<!--kg-card-begin: markdown-->
```
$ java -cp modules/openapi-generator-cli/target/openapi-generator-cli.jar org.openapitools.codegen.OpenAPIGenerator generate -g java -o out -i petstore.yaml --global-property debugModels=true

```
<!--kg-card-end: markdown-->

I won't print the entire output here because it's huge, but as part of the output it will basically spit a giant json representation of all the models available inside that specified yaml file. Here's a tiny part of the beginning :

<!--kg-card-begin: markdown-->
```
[ {
  "importPath" : "org.openapitools.client.model.Category",
  "model" : {
    "anyOf" : [],
    "oneOf" : [],
    "allOf" : [],
    "name" : "Category",
    "classname" : "Category",
    "title" : "Pet category",
    "description" : "A category for a pet",
    "classVarName" : "category",
    "modelJson" : "{\n \"title\" : \"Pet category\",\n \"type\" : \"object\",\n \"properties\" : {\n \"id\" : {\n \"type\" : \"integer\",\n \"format\" : \"int64\"\n },\n \"name\" : {\n \"type\" : \"string\"\n }\n },\n \"description\" : \"A category for a pet\",\n \"xml\" : {\n \"name\" : \"Category\"\n }\n}",
    "dataType" : "Object",
    "xmlName" : "Category",
    "classFilename" : "Category",
    "unescapedDescription" : "A category for a pet",
    "isAlias" : false,
    "isString" : false,
    "isInteger" : false,
    "isLong" : false,
    "isNumber" : false,
    "isNumeric" : false,
    "isFloat" : false,
    "isDouble" : false,
    "isDate" : false,
    "isDateTime" : false,
    "isDecimal" : false,
    "isShort" : false,
    "isUnboundedInteger" : false,
    "isPrimitiveType" : false,
    "isBoolean" : false,
    "additionalPropertiesIsAnyType" : false,
    .........

```
<!--kg-card-end: markdown-->
## Running and Debugging a generator

Whether you want to play with an existing generator or [create a new one](https://openapi-generator.tech/docs/new-generator/), the existing documentation tends to offer you to compile and run the generators using the generic `./mvnw clean package` followed by `./bin/generate-samples.sh bin/configs/spring-boot.yaml` (replace with the file you want to use) command. The first one will compile the source, while the second one will use the created `openapi-generator-cli.jar` and actually run the code.

For example, the config file `spring-boot.yaml` :

<!--kg-card-begin: markdown-->
```
generatorName: spring
outputDir: samples/server/petstore/springboot
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
additionalProperties:
  artifactId: springboot

```
<!--kg-card-end: markdown-->

will run the command

<!--kg-card-begin: markdown-->
```
$./modules/openapi-generator-cli/target/openapi-generator-cli.jar org.openapitools.codegen.OpenAPIGenerator generate \
-g spring \
-i modules/openapi-generator/src/test/resources/2_0/petstore.yaml \
-o samples/server/petstore/springboot \
-t modules/openapi-generator/src/main/resources/JavaSpring \
--additional-properties=artifactId=springboot

```
<!--kg-card-end: markdown-->

Useful, but quite cumbersome. On top of this, you typically want to be able to run / debug code as you go directly in your IDE.

Using IntelliJ, you can do it by creating a run configuration as such :

![Getting started with OpenAPI Generators : tips and tricks](https://lengrand.fr/content/images/2022/12/image.png)
_A run configuration in IntelliJ used to run a specific generator_

Set the `OpenAPIGenerator` class to run from the `openapi-generator-cli` jar file. Pick your generator name, input yaml file and output folder (the same as in the config file described above and set the working directory to be the root of the `openapi-generator` git project. You're done!

Now you can go in the generator's `CodeGen` file, (for example `JMeterClientCodegen` if your generator name is `jmeter` ) and set breakpoints where you want 😊.

## Setting breakpoints in the right locations

As described above already OpenAPI generators take a specification file, transform it into a set of objects in memory, and use those objects to generates code / files using [mustache](http://mustache.github.io/) template files.

Typically, generators will take those existing objects and add or modify some of their content to fit the output to be generated. Most generators will extend from `DefaultCodeGen`. That's where you will find the most useful locations to set breakpoints to see what to change and where.

The most interesting part of this class is located in the `generate` method. You will also be able to find the lines that are being used to print the debugging flags by searching for the `Json.prettyPrint` calls. Here's an example for the models (as of now, [line 566 of](https://github.com/OpenAPITools/openapi-generator/blob/7c587ce061f1b2ef6bcd3fc406224452f79099a9/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java#L572) [`DefaultCodeGen`](https://github.com/OpenAPITools/openapi-generator/blob/7c587ce061f1b2ef6bcd3fc406224452f79099a9/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java#L572) :

<!--kg-card-begin: markdown-->
```
if (GlobalSettings.getProperty("debugModels") != null) {
    LOGGER.info("############ Model info ############");
    Json.prettyPrint(allModels);
}

```
<!--kg-card-end: markdown-->

![Getting started with OpenAPI Generators : tips and tricks](https://lengrand.fr/content/images/2022/12/image-1.png)
_A screenshot of a debug of the model, showing the content of the "allModels" variable_

Once you're in there, you can dive into the data and find out what you want to do with it.

## Extending the default generator

(Thanks [Beppe](https://twitter.com/beppecatanese) for the tip!)

Most generators typically add extra bits of necessary information inside their objects, for example inside the bundle for supporting files : `bundle.put("distinctPathParameters", distinctPathParameters);` . The trick is to find _where_ to do this.

Luckily for us, the smart developers of OpenAPI have created locations to do just that! You'll want to search for the methods called `postProcess*` in `DefaultCodeGen`, those are placeholders that are set at the end of the various `generate`methods that you can override at your convenience in your custom generator.

Here is what a completely useless generator could do :

<!--kg-card-begin: markdown-->
```
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> bundle) {
    bundle.put("bloggingAt1AM", "isFun");

    return bundle;
}

```
<!--kg-card-end: markdown-->

Which you could then use inside a `README.mustache` template, for example :

<!--kg-card-begin: markdown-->
```
# Important announcement

{{bloggingAt1AM}} // Will print "isFun" once ran

```
<!--kg-card-end: markdown-->
## Generating custom lambdas

One of the super powers of mustache is its lambdas, which you can declare in the templates. There is a [list available](https://mustache.github.io/mustache.5.html) on the mustache website, but the OpenAPI templates define a few more. You can search the code for any class implementing the `Mustache.Lambda` interface 😊.

![Getting started with OpenAPI Generators : tips and tricks](https://lengrand.fr/content/images/2022/12/image-2.png)
_A list of many custom lambdas in the OpenAPI source code_

You can easily create new lambdas as well by implementing that interface yourself.

Here is a concrete example : Typically, parameters are surrounded with braces when using a generator. For example, for a GET request, with a `petId` parameter it will come out like this : `DELETE http://petstore.swagger.io/v2/pet/{petId}`.

That being said, The [Jetbrains HTTP Client](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html) defines parameter with double braces (!). I need this to have a valid call : `DELETE http://petstore.swagger.io/v2/pet/{{petId}}`.

Instead of having to play around a lot with the templating, I decided to create a custom lambda for this in my generator. This is how it looks like :

```
public class JetbrainsHttpClientClientCodegen extends DefaultCodegen implements CodegenConfig {

    @Override
    protected ImmutableMap.Builder<String, Mustache.Lambda> addMustacheLambdas() {
       return super.addMustacheLambdas()
                .put("doubleMustache", new DoubleMustacheLambda());
    }

    public static class DoubleMustacheLambda implements Mustache.Lambda {
        @Override
        public void execute(Template.Fragment fragment, Writer writer) throws IOException {
            String text = fragment.execute();
            writer.write(text
                    .replaceAll("\\{", "{{")
                    .replaceAll("}", "}}")
            );
        }
    }
}
```

Two things happen here :

- I create a `DoubleMustacheLambda` class that implements `Mustache.Lambda` that  itself implements the `execute` method. The execute method does nothing else than rewriting some of the generated text.
- I override the `addMustacheLambdas` method, and use it (just like for my data in the previous tip) to insert my custom lambda.

Once that is done, I can use it inside my `api.mustache` template! For example :  `{{#lambda.doubleMustache}}{{path}}{{/lambda.doubleMustache}}`

## A word of conclusion

I hope those tips will help you hit the ground running with OpenAPI generators. Most of the tips directly come from the open [Slack channel](https://join.slack.com/t/openapi-generator/shared_invite/zt-12jxxd7p2-XUeQM~4pzsU9x~eGLQqX2g), the folks there are super useful. The [official documentation](https://openapi-generator.tech/) is nice, but I honestly found it quite sparse, and once you dive in, a lot of the advice comes down to "have a look at the other generators for inspiration". I find it logical, because in 99% of the cases, the generator that you need already exists! If it doesn't though, you're in for some fun.

Hopefully I'll save you a couple hours this way!

Don't hesitate to reach out if you have any questions! I'm mostly available on [Mastodon](https://mastodon.online/@jlengrand) and [Linkedin](https://www.linkedin.com/in/julienlengrand/) those days 😊, though you can still find me on [Twitter](https://twitter.com/jlengrand)..