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 withdelegatePattern: true;.openapi-generator-ignoreis read.server fastapi: theimplpackage, the tests of the APIs andtests/conftest.py, written only when missing;.openapi-generator-ignoreis read.server express: the handlers, in files of your own, that the generated router calls.server aspnet:Program.csand the stub implementations, written only when missing.server go: your implementation of the generated interfaces, andmain.gowithmain: 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,--engineandmeta: the output changes through the options, an overlay and thex-apigenieextensions 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.