Generate endpoint definitions from an OpenAPI YAML

Note

This is a really early alpha implementation.

Installation steps

Add the sbt plugin to the project/plugins.sbt:

addSbtPlugin("com.softwaremill.sttp.tapir" % "sbt-openapi-codegen" % "1.10.5")

Enable the plugin for your project in the build.sbt:

enablePlugins(OpenapiCodegenPlugin)

Add your OpenApi file to the project, and override the openapiSwaggerFile setting in the build.sbt:

openapiSwaggerFile := baseDirectory.value / "swagger.yaml"

At this point your compile step will try to generate the endpoint definitions to the sttp.tapir.generated.TapirGeneratedEndpoints object, where you can access the defined case-classes and endpoint definitions.

Usage and options

The generator currently supports these settings, you can override them in the build.sbt;

setting

default value

description

openapiSwaggerFile

baseDirectory.value / “swagger.yaml”

The swagger file with the api definitions.

openapiPackage

sttp.tapir.generated

The name for the generated package.

openapiObject

TapirGeneratedEndpoints

The name for the generated object.

openapiUseHeadTagForObjectName

false

If true, put endpoints in separate files based on first declared tag.

openapiJsonSerdeLib

circe

The json serde library to use.

openapiValidateNonDiscriminatedOneOfs

true

Whether to fail if variants of a oneOf without a discriminator cannot be disambiguated.

openapiMaxSchemasPerFile

400

Maximum number of schemas to generate in a single file (tweak if hitting javac class size limits).

The general usage is;

import sttp.apispec.openapi.circe.yaml._
import sttp.tapir.generated._
import sttp.tapir.docs.openapi._

val docs = TapirGeneratedEndpoints.generatedEndpoints.toOpenAPI("My Bookshop", "1.0")

Output files

To expand on the openapiUseHeadTagForObjectName setting a little more, suppose we have the following endpoints:

paths:
  /foo:
    get:
      tags:
        - Baz
        - Foo
    put:
      tags: [ ]
  /bar:
    get:
      tags:
        - Baz
        - Bar

In this case ‘head’ tag for GET /foo and GET /bar would be ‘Baz’, and PUT /foo has no tags (and thus no ‘head’ tag).

If openapiUseHeadTagForObjectName = false (assuming default settings for the other flags) then all endpoint definitions will be output to the TapirGeneratedEndpoints.scala file, which will contain a single object TapirGeneratedEndpoints.

If openapiUseHeadTagForObjectName = true, then the GET /foo and GET /bar endpoints would be output to a Baz.scala file, containing a single object Baz with those endpoint definitions; the PUT /foo endpoint, by dint of having no tags, would be output to the TapirGeneratedEndpoints file, along with any schema and parameter definitions.

Json Support

openapiJsonSerdeLib

required dependencies

Conditional requirements

circe

“io.circe” %% “circe-core” “io.circe” %% “circe-generic”

“com.beachape” %% “enumeratum-circe” (scala 2 enum support). “org.latestbit” %% “circe-tagged-adt-codec” (scala 3 enum support).

jsoniter

“com.github.plokhotnyuk.jsoniter-scala” %% “jsoniter-scala-core” “com.github.plokhotnyuk.jsoniter-scala” %% “jsoniter-scala-macros”

Limitations

Currently, string-like enums in Scala 2 depend upon the enumeratum library ("com.beachape" %% "enumeratum"). For Scala 3 we derive native enums, and depend on "io.github.bishabosha" %% "enum-extensions" for generating query param serdes. Other forms of OpenApi enum are not currently supported.

Models containing binary data cannot be re-used between json and multi-part form endpoints, due to having different representation types for the binary data

We currently miss a lot of OpenApi features like:

  • tags

  • anyOf/allOf

  • missing model types and meta descriptions (like date, minLength)

  • file handling