Generating the API client

Generator selection

The OpenAPI Generator supports generating clients in over 60 language/library combinations, which you can list by running java -jar openapi-generator-cli.jar list . For our purposes, we’re only interested in the Dart generators, of which there are three at the time of writing:

dart

Uses the http package as its HTTP client, and this is the only direct dependency of the generated client. Model classes are generated as Plain Old Dart Objects (PODOs) with toJson and fromJson methods.

dart-dio

Uses the dio package as its HTTP client, and built_value to generate models and their serializers.

dart-jaguar

Uses the jaguar-retrofit and jaguar-serializer pair as the HTTP client and serializer, respectively.

We’ll look at dart-dio specifically since that’s what I’m most familiar with, but the other generators should work similarly.

Generator configuration

First, let’s look at the configuration options for this generator. We can define these settings in an open-generator-config.yaml file that we can pass to the generator, for example:

# Config options for the dart-dio generator

pubName: my_api

pubVersion: 0.0.1

pubDescription: "My API Client"

If you want the generator to automatically format your code, you’ll need to set a DART_POST_PROCESS_FILE environment variable pointing to dartfmt -w in your Dart SDK’s path. Some generators will inform you about this if the variable is not set.

The help command will document all the options for the generation command, but at a minimum, we’ll need to feed it the spec file as input ( -i ) and specify a generator ( -g ).

We’re additionally passing the generator configuration file ( -c ) and enabling the automatic code formatting ( --enable-post-process-file ).

If you want to not generate test classes, there’s -DapiTests=false and -DmodelTests=false , as well as -DapiDocs=false for documentation.

There’s a slew of other options that you can explore, like selectively generating only certain parts of the API, bringing in your own pre-generated models, or ignoring generating certain files (the generator should create an .openapi-generator-ignore file where you can add exclusions).

Running the generator

Finally, let’s generate the client:

java -jar openapi-generator-cli.jar generate -i petstore.yaml -g dart-dio -c open-generator-config.yaml --enable-post-process-file

Et voilà, a fresh API client package.

Or so I’d like to say, but in the case of this particular generator, we’re going to have to run

flutter pub run build_runner build

to generate our built_value models and complete the process for good.

As a small troubleshooting tip on this step, if any of your generated model classes is named the same as a class in dart:core (e.g. Error or Match ) you will probably run into the problem described in this GitHub issue, which you can solve by hiding the offending classes in the generated serializers.dart file:

import 'dart:core' hide Error;

and then running the flutter pub run build_runner build command again.

Sadly, if this is the case, which it will be if you used the sample spec file linked above, you’re probably going to have to do this every time you regenerate the client, at least until you’re comfortable enough with the toolset to write your own codegen templates, which use the Mustache templating system.

The preceding paragraph marks this as a good point for a reality check: code generation is not perfect, especially not when it tries to cast such a wide net as OpenAPI Generator. You are likely to run into errors and things might not work out-of-the-box without some trial-and-error.

Take this exercise as a starting point to offload some of the boilerplate and validate your API spec. If you have the ability to change your spec, customize an existing generator’s options or even write your own generator to the point it all works flawlessly with just a couple commands, you’re one step closer to the code equivalent of Midas’ Golden Touch.