Mustache templates with OpenAPI specs
Tags: api, openapi, mustache
Published: 2022-06-15 09:58:50

This article explores the Mustache templates, in the context of the OpenAPI specification, and **the underrated features that can help developers** in optimizing the code generation.

At [Adyen](https://www.adyen.com) we adopted OpenAPI specs some time ago and we have created our own Mustache templates to streamline the generation of the [Adyen SDKs](https://github.com/Adyen) (in various languages) every time there is a new release of the payment APIs.

[Mustache](https://mustache.github.io) is a logic-less template framework used to generate output that must conform to a structure and format we want to control. The applications are several: generating code, HTML, configuration files, etc…

They are logic-less (meaning the actual templating engine must take care of the conversion logic), simple (having just the features you need — no-frills) and open-source.

## In a nutshell
Given a template

```
Hello {{name}} {{lastname}}
```
and a data structure

```
{
  "name": "Beppe",
  "lastname": "Catanese"
}
```
the template engine will know how to produce.

```
Hello Beppe Catanese
```

## OpenAPI language templates
The [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) project allows the generation of (client, server and models) code starting from a valid OpenAPI specification, either `json` or `yaml`. This is an extremely valuable feature for API-driven products where code and API specs change often and need to keep aligned (at ideally small effort).

In this workflow Mustache templates play a key role: for each language and framework OpenAPI provides a default implementation (based on predefined Mustache templates) which works really well in most cases and can be tuned further (extending the templates) when needed.

## Becoming a Mustache master
Let’s dive into the more advanced features that make Mustache templates really powerful.

### Parameters list
Use `^last` to add the comma between parameters unless it is the last one
```
{{#allParams}}paramName *{{{dataType}}}{{^last}}, {{/last}}{{/allParams}}
-> user *string, address *string, nationality *string
```

### Naming parameters with a sequence
Use -index to access the index while traversing an array or list
```
{{#allParams}}req{{-index}} *{{{dataType}}}{{^last}}, {{/last}}{{/allParams}}
-> req1 *string, req2 *string, req3 *string
```
### Distinguish between parameters
While `allParams` gives access to the whole list of parameters, it is useful to make a distinction when generating method signatures or documentation
```
{{#pathParams}}...{{/pathParams}}
{{#bodyParams}}...{{/bodyParams}}
{{#queryParams}}...{{/queryParams}}
```

###Comments
Comments are useful in templates too, but rarely seen
```
/**
Info about the method 
{{! comments to be ignore when parsing the template}} 
**/
```

### Custom delimiter
The default delimiters `{{` and `}}` can be overridden (some scripting languages use brace brackets)
```
{{! change delimiters to <% and %>}}
{{=<% %>=}}
```

### First and last element
While traversing arrays it is useful to access easily the first and the last element, for example the [Go imports](https://go.dev/tour/basics/2) group all modules in a list starting and finishing with parenthesis
```
{{#-first}}
import (
{{/-first}}
    "{{import}}"
{{#-last}}
)
{{/-last}}
-> import (
     "fmt"
     "math"
   )
```

###Lamba functions
There is a small set of functions available during the OpenAPI codegen phase: those are convenient when you need to lowercase a package name or camelCase a method.
```
lowercase(Beppe) -> beppe
uppercase(Beppe) -> BEPPE
titlecase(Beppe likes mustache) -> Beppe Likes Mustache
camelcase(Beppe-Catanese) -> BeppeCatanese
indented -> add indentation
```
### Create custom generator
When specific customisation is necessary OpenAPI codegen allows to extend the specific-language generator to add (or redefine) the generation logic. The approach by extension is pretty straight-forward:

1: extend the client code generator (for example implementing the renaming of the operationId attribute)

2: generate the code using the new generator

See my gist [MyGoClientCodegen](https://gist.github.com/gcatanese/6b84046488c4d62ac0eb4110a9cb52e8#file-mygoclientcodegen-java)

Generate the client code using the new CodeGen implementation
```
java -jar openapi-generator-cli.jar generate \
-i /openapi.yaml -t templates/go -g go \
-p packageName=Checkout -o src/checkout \
-g org.mycompany.codegen.MyGoClientCodegen
```
###Conclusion
Check out our [Go Library](https://github.com/Adyen/adyen-go-api-library) to see the customisation of the Mustache templates and how the code generation is performed starting from the [Adyen OpenAPI specs](https://github.com/Adyen/adyen-openapi). And get ready for more articles and insights around our work with OpenAPI (i.e generating server stubs, testing, mocking and validation).

Lateeeeeer!