Migrate from OpenAPI Generator

This guide moves a repository that generates clients or servers with OpenAPI Generator to apigenie-generator: the generator names, the options, the files you own, the build and the CI step, and what has no counterpart. It starts from OpenAPI Generator 7.x, run as openapi-generator-cli, from its Maven or Gradle plugin or from the npm wrapper, and an OpenAPI file, openapi.yaml.

You need the CLI installed; the Quickstart shows how. Keep OpenAPI Generator until the last step: the two can generate into separate directories while you compare.

What changes and what stays

OpenAPI Generator API Genie
Command openapi-generator-cli generate -g spring -i openapi.yaml -o server apigenie-generator server spring openapi.yaml -o server
Targets 172 generators, in Java, Kotlin, Swift, Rust, PHP and more 6 clients and 8 servers from OpenAPI, 14 targets from AsyncAPI, a documentation site, example data (the list)
Input OpenAPI 2.0 and 3.x OpenAPI 3.0 to 3.2; Swagger 2.0 through apigenie convert; AsyncAPI 3, GraphQL, Protobuf, JSON Schema
Options --additional-properties a=b,c=d, -c config.yaml -p a=b -p c=d, commands.generate.<target> of apigenie.yaml
Files you own .openapi-generator-ignore, --skip-overwrite the implementation files, written only when missing; .openapi-generator-ignore for Spring, Java and FastAPI
Changing the output Mustache and Handlebars templates, -t an overlay and the x-apigenie extensions, no templates
Checking the input --skip-validate-spec to skip it always; apigenie lint says what to fix
Runtime Java 11 or later a native binary: archives, .deb, .rpm, npm, Homebrew, Docker
Build plugins Maven, Gradle none; a step before the build, or generated code checked in and verified in CI

Run both on the same document

openapi-generator-cli generate -g typescript-fetch -i openapi.yaml -o client-oag
apigenie-generator client fetch openapi.yaml -o client --package-name shipping-client

The target comes first, as two words, and the input comes last; -i and -g are gone, -o stays. The output is an npm package with no runtime dependency: requests go through the global fetch(), and each operation is an async function named after its operationId, taking one object of parameters, as useSingleRequestParameter gives in OpenAPI Generator. Generate a client and a server shows the client in use.

The generators by name

OpenAPI Generator API Genie Note
typescript-fetch, typescript-axios, typescript-node client fetch one TypeScript client on the global fetch(), for browsers and Node.js 18 or later; layout: sources for a bundler
java client java --library restclient (default), resttemplate, feign or http-interface: the client depends on Spring Framework, not on OkHttp or Jersey
spring server spring the same code and options, in place (below)
python client python httpx and Pydantic 2
python-fastapi server fastapi the same layout and options, in place (below)
go client go net/http; layout: module writes go.mod
go-server, go-gin-server server go net/http
csharp client csharp HttpClient with IHttpClientFactory registration; target_framework: net8.0 to net10.0
aspnetcore server aspnet Minimal APIs
elixir client elixir Req
nodejs-express-server server express TypeScript, typed handlers, requests validated with Ajv or generated validators
html, html2, markdown, asciidoc, dynamic-html docs one site for several documents, with Try it out and search
openapi, openapi-yaml apigenie convert, apigenie bundle and apigenie format
kotlin, swift6, rust, dart, php, ruby, scala-*, cpp-*, kotlin-spring, java-* servers, python-flask, rust-server, … no counterpart keep OpenAPI Generator for these targets; both can run in one repository

The other commands: openapi-generator-cli validate is apigenie lint, list is the help of apigenie-generator, which names the targets, config-help -g is the Configuration section of the target’s page, and batch is one apigenie.yaml with a section per target and one command per target. meta, which starts a generator of your own, has no counterpart.

Option by option

OpenAPI Generator API Genie
-i openapi.yaml the last argument
-g NAME the target, client fetch, server spring, …
-o DIR -o DIR
-c config.yaml -c apigenie.yaml, section commands.generate.<target>
--additional-properties a=b,c=d -p a=b -p c=d, or the keys of that section
--package-name, npmName, packageName --package-name: the npm package, the Python distribution, the Go package, the C# namespace, the Java base package, the Mix application
--artifact-version, npmVersion, packageVersion --package-version
--library --library of client java; library of server spring
--invoker-package, --api-package, --model-package, --group-id, --artifact-id basePackage, apiPackage, modelPackage, groupId, artifactId of client_java and server_spring
--type-mappings, --import-mappings typeMappings and importMappings (Java, Spring), type_mappings (Go)
--model-name-prefix, --model-name-suffix model_suffix (C#, ASP.NET), modelNamePrefix (FastAPI)
--global-property apis or models include_tags and exclude_tags (Go, Elixir, Phoenix), generate: [types] (server go)
--inline-schema-name-mappings class_overrides (Python), module_overrides (Elixir, Phoenix)
--openapi-normalizer an overlay, for the changes that fit one
useTags useTags (Java, Spring), grouping: tag (C#, ASP.NET, Express), group_by: tag (Python)
--skip-validate-spec, -t, --engine, --minimal-update, --dry-run, -s, --server-variables, --remove-operation-id-prefix, --git-*, --release-note, --http-user-agent, --enable-post-process-file no counterpart

An option a target does not know is an error, not ignored, so a copied configuration says at once what did not carry over.

Keep your code out of the generated files

OpenAPI Generator protects your files with .openapi-generator-ignore and --skip-overwrite. Each server target of apigenie-generator has a place for your code that regenerating never touches:

  • server spring: the controllers, written only when missing, or the delegates with delegatePattern: true; .openapi-generator-ignore is read.
  • server fastapi: the impl package, the tests of the APIs and tests/conftest.py, written only when missing; .openapi-generator-ignore is read.
  • server express: the handlers, in files of your own, that the generated router calls.
  • server aspnet: Program.cs and the stub implementations, written only when missing.
  • server go: your implementation of the generated interfaces, and main.go with main: true, written only when missing.
  • server phoenix: your implementations of the generated behaviours.

client java writes .openapi-generator-ignore too. For the other targets, generate into a directory of its own: everything in it is generated, and your code lives next to it.

Regenerate a Spring or FastAPI project in place

server spring produces the code of OpenAPI Generator’s spring generator and accepts the same options; server fastapi has the layout and the options of python-fastapi. A project generated by OpenAPI Generator is generated again by apigenie-generator, in the same directory, with the same .openapi-generator-ignore. The config.yaml of OpenAPI Generator:

basePackage: com.acme.pets
delegatePattern: true
useBeanValidation: true

goes under the target in apigenie.yaml, as it is or under an additionalProperties key:

version: '1.0'
commands:
  generate:
    server_spring:
      basePackage: com.acme.pets
      delegatePattern: true
      useBeanValidation: true
apigenie-generator server spring openapi.yaml -o server
git diff --stat server

The differences each page lists under “Differences from openapi-generator” show up in that diff: for Spring, useSpringBoot3 is true by default and the files are marked @Generated(value = "API Genie"); for FastAPI, routes declare their status code and response class, the models are Pydantic 2 models without to_dict() and from_dict(), and oneOf is a union. Both read OpenAPI 3.0 to 3.2 only: apigenie convert --to openapi32 for a Swagger 2.0 document, apigenie bundle for one that references other files.

The build and CI

The Maven plugin’s generate-sources execution and the Gradle openApiGenerate task become a command before the build, since apigenie-generator is a binary rather than a plugin: an exec-maven-plugin execution, a Gradle Exec task, or an npm script with the CLI from the @mykulyak/api-genie package, which pins its version in package.json as openapitools.json did. In Docker, mykulyak/apigenie runs it with --entrypoint apigenie-generator.

Or generate into the repository and let CI check that the generated code matches the contract:

apigenie-generator client fetch openapi.yaml -o client --package-name shipping-client
apigenie-generator server spring openapi.yaml -o server
git diff --exit-code client server

The step fails when someone edited the generated code by hand or forgot to regenerate.

What has no counterpart

  • The targets listed above as such. Kotlin, Swift, Rust, Dart, PHP, Ruby, Scala and C++ clients, and the servers other than Spring, FastAPI, Express, ASP.NET Core, Go and Phoenix.
  • Templates and custom generators. -t, --engine and meta: the output changes through the options, an overlay and the x-apigenie extensions each target’s page lists.
  • Maven and Gradle plugins, replaced by a step before the build.
  • --skip-validate-spec. A document the generator cannot use stops it with exit status 2.

Remove OpenAPI Generator

When the generated projects build and their tests pass: remove @openapitools/openapi-generator-cli and openapitools.json, or the plugin from pom.xml and build.gradle, delete the .openapi-generator/ directories and the .openapi-generator-ignore files of the targets that do not read them, and replace the generation step in CI.

Was this helpful?