Mustache templates with OpenAPI specs

gcatanese

Beppe Catanese

Posted on June 15, 2022

Mustache templates with OpenAPI specs

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 we adopted OpenAPI specs some time ago and we have created our own Mustache templates to streamline the generation of the Adyen SDKs (in various languages) every time there is a new release of the payment APIs.

Mustache 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}}
Enter fullscreen mode Exit fullscreen mode

and a data structure

{
  "name": "Beppe",
  "lastname": "Catanese"
}
Enter fullscreen mode Exit fullscreen mode

the template engine will know how to produce.

Hello Beppe Catanese
Enter fullscreen mode Exit fullscreen mode

OpenAPI language templates

The 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}}
Enter fullscreen mode Exit fullscreen mode

Comments

Comments are useful in templates too, but rarely seen

/**
Info about the method 
{{! comments to be ignore when parsing the template}} 
**/
Enter fullscreen mode Exit fullscreen mode

Custom delimiter

The default delimiters {{ and }} can be overridden (some scripting languages use brace brackets)

{{! change delimiters to <% and %>}}
{{=<% %>=}}
Enter fullscreen mode Exit fullscreen mode

First and last element

While traversing arrays it is useful to access easily the first and the last element, for example the Go imports group all modules in a list starting and finishing with parenthesis

{{#-first}}
import (
{{/-first}}
    "{{import}}"
{{#-last}}
)
{{/-last}}
-> import (
     "fmt"
     "math"
   )
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

Conclusion

Check out our Go Library to see the customisation of the Mustache templates and how the code generation is performed starting from the Adyen OpenAPI specs. And get ready for more articles and insights around our work with OpenAPI (i.e generating server stubs, testing, mocking and validation).

Lateeeeeer!

💖 💪 🙅 🚩
gcatanese
Beppe Catanese

Posted on June 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related