This plugin was originally designed for use by the OpenAPi v3 Maven Plugin, but works with the command line generator and the Gradle plugin. it generates excellent Dart code and uses Dio.
This tool can be used via Maven, Gradle or from the command line. There are important additional properties that you can configure especially around support for null safety, so read on!
To use it, do something like this:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.0.0</version>
<dependencies>
<dependency>
<groupId>com.bluetrainsoftware.maven</groupId>
<artifactId>openapi-dart-generator</artifactId>
<version>5.5</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>mr-api</id>
<goals>
<goal>generate</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<output>${project.basedir}</output>
<inputSpec>${project.basedir}/target/mrapi/mr-api.yaml</inputSpec>
<generatorName>dart2-api</generatorName>
<enablePostProcessFile>true</enablePostProcessFile>
<additionalProperties>
<additionalProperty>
pubName=k8s_api
</additionalProperty>
</additionalProperties>
</configuration>
</execution>
</executions>
</plugin>
We use the enablePostProcessFile because if it finds a FLUTTER environment variable, it will run dartfmt on the generated files.
In Gradle, you have to make this extra library available to the buildscript, so at the top of your file before your plugin declaration you need a section similar to:
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "com.bluetrainsoftware.maven:openapi-dart-generator:5.4"
}
}
from there in your openApiGenerator definitions, you specify the server format in additional properties:
openApiGenerate {
generatorName = "dart2-api"
inputSpec = openApiSpec
outputDir = openApiOutputDir
apiPackage = "com.your-company.api"
modelPackage = "com.your-company.api.model"
additionalProperties = [
'key': 'value'
]
configOptions = [:]
}
Please refer to the article on Medium.
Additional properties allow you to customise how code is generated and we honour 2 of them above the normal ones.
-
pubspec-dependencies
: anything in this will be split on a command added to the dependencies section of your generated code. -
pubspec-dev-dependencies
: anything here will be added to the dev dependencies of your generated code. -
nullSafe=true' and `nullSafe-array-default=true
- these two normally go together and change the minimum version of Dart to 2.12 and generate null safe code. Using the nullSafe-array-default, it makes even arrays that are not listed as beingrequired
in your OpenAPI "required" but making them always generate a default value of[]
. This ends up being considerably easier to use. -
listAnyOf=false
- this will turn off AnyOf support. This would be a bit weird, but you can do it if you want.
the normal ones include:
name: {{pubName}} version: {{pubVersion}} description: {{pubDescription}}
They are specified in the configuration above (Maven example here):
<configuration>
<output>${project.basedir}</output>
<inputSpec>${project.basedir}/target/mrapi/mr-api.yaml</inputSpec>
<generatorName>dart2-api</generatorName>
<enablePostProcessFile>true</enablePostProcessFile>
<additionalProperties>
<additionalProperty>pubName=myapi</additionalProperty>
</additionalProperties>
</configuration>
See the src/it
project for more examples.
You may need to use additional files - just add them to the project or add them via a dependency. You can use the
importMappings
section of the configuration to bring in any packages (internal or external) into the library
definition. For example
<typeMappings>int-or-string=IntOrString</typeMappings>
<importMappings>IntOrString=./int_or_string.dart</importMappings>
This will note anything that has format: int-or-string
and map this to the class IntOrString and there will be an
extra part
import for it added to the library main. You must write this class to have the expected criteria from
the rest of the library but it does allow you to support custom types. Again, an example of this is in src/it
.
If you use something like this instead:
<typeMappings>int-or-string=IntOrString</typeMappings>
<importMappings>IntOrString=package:k8s-dart/int_or_string.dart</importMappings>
Then it will add it to the import
section of your library allowing
you to use external libraries.
We typically use the Dependency Plugin to copy the actual OpenAPI yaml file from a different project - such as in this case "mr-api".
Note
|
you can also customise this using my MergeYaml plugin if you wish to merge apis together. If often do this for testing purposes. |
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack todo api</id>
<phase>initialize</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>io.yourapi.mr</groupId>
<artifactId>mr-api</artifactId>
<version>1.1-SNAPSHOT</version>
<type>jar</type>
<outputDirectory>${project.basedir}/target/mrapi/</outputDirectory>
</artifactItem>
</artifactItems>
<includes>
**/*.yaml
</includes>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
And we include a custom Clean plugin definition to ensure old artifacts aren’t left behind as you generate.
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<filesets>
<fileset>
<directory>lib</directory>
<includes>
<include>**/**</include>
</includes>
</fileset>
<fileset>
<directory>docs</directory>
<includes>
<include>**/**</include>
</includes>
</fileset>
<fileset>
<directory>test</directory>
<includes>
<include>**/**</include>
</includes>
</fileset>
<fileset>
<directory>.openapi-generator</directory>
<includes>
<include>**/**</include>
</includes>
</fileset>
<fileset>
<directory>.openapi-generator</directory>
<includes>
<include>**/**</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
If you are trying to make changes to the repository, I recommend adding a new test to "SampleRunner"
with your options - you can change it to point to your own yaml OpenAPI file and it will generate the project
into target/SampleRunner
. Also open this project (from target/SampleRunner
) in the IDE and you will be able to
run the test and regenerate the project (just don’t do a mvn clean).
If you run and debug the test in the IDE it means you can see what OpenAPI is putting in what places and see the breakdown of the structures and tagging that is going on.
If you add something, please make sure you provide integration tests - so add the parts of the yaml that don’t
otherwise work to the projects in src/it/* projects and run the mvn verify
command. Please make sure you add tests
to the test subfolder to ensure the code is generating and working the way you want, especially if you add stuff
to the deep copy mechanism, the hash or equals mechanisms.
To test locally you can run tests by invoking this command:
mvn clean verify
The source for the tests is located in src/k8s folders. The generated test output will be in target/it/k8s.
-
5.7 - includes fix for enums that contain spaces
-
5.5 - this is a release focused on form, multi-part uploads, file uploads and downloads and enhancing the parameters as lodged in a couple of tickets. This release deletes unused models from Inline form models.
-
5.4 - change the equals method to use a local variable called
__other
instead ofother
as when a class had another
property, the equals would break. -
5.3 - AnyOf support contribution by Łukasz Wiśniewski (https://github.com/vishna) and a resolution of the application/octet-stream issue where binary data is now returned as an ApiResponse (always).
-
5.2 - this version addresses issues with complex codegen. It assumes that by default List and Map entries will be non null for null safe support.
-
5.1 - this addresses the issues of a non-required POST body. It does not address the issue of complex tree structures of models as yet, this will come in 5.2.
-
5.0 - is a significant departure and you will need to use the public Dart tool to migrate your code https://pub.dev/packages/openapi_migrate/versions/1.0.0 It allows the use of null safe code by adding in the extra additionalProperty
nullSafe
. It will also allow you to assume (and ensure defaults are set) null safety for all arrays that are otherwise not declared such in your OpenAPI yaml (by making them empty arrays) by the use ofnullSafe-array-default
.
-
It is recommended for 5.0 that you do an intermediate step and regenerate your existing code without these null safe functions turned on,
and use the openapi_migrate
tool on your code. Its likely you will need to run it multiple times to catch everything. When you are ready
to move your whole project to null safety, you will be able to regenerate your API with the additionalProperty flags and then do the normal
dart migrate
process. We are doing this with our codebase over at FeatureHub (https://featurehub.io).
Another significant departure for 5.0 is that it enforces return vaulues - you cannot return a status code from an API that is not declared in your OpenAPI.
-
4.2 - if you directly use the Type Transformers for enums, this is a breaking change. They have changed to extensions and have been slightly remodeled based on Robert’s inlining work. The whole deserialisation mechanism has changed particluarly for lists and maps because it wasn’t able to cope more than one level deep with lists and maps (issue #19). The date format now serialises directly properly, but not in lists.
-
4.1 - support for OpenAPI v5, released 2020/12/21. Next release will support null types in Dart. Please note that with the move to 4.1, form models are by default NOT generated, so your parameters for methods calling forms won’t work. You need to set a global property called
skipFormModels
to false. In Maven this is in the configuration
<globalProperties>
<skipFormModels>false</skipFormModels>
</globalProperties>
-
3.10 - support extension methods for mapping between enum names and types
-
3.9 - support for reserved words mappings in variable names
-
3.8 - non complex lists were not being compared in equals or hash functions correctly
-
3.7 - resolved an issue with inline enums - thanks to Robert of https://github.com/BlackBeltTechnology
-
3.5 - resolved an issue where class level variables were being duplicated from the parent, causing equals to fail
-
3.4 - backed out some experimental features and exposed the serialization capabilities. fixed a NPE on the copyWith.
-
3.3 - introduces feedback from Jpi & Brian Janssen around making all the LocalApi serializer calls static, so
toJson()
can be called by jsonEncode without introducing non-Dart-like complexity. Further, we introduce an experimental vendor extension on an operation calledx-dart-rich-operationId
- this has to be another operation id, not the same asoperationId:
as Dart cannot have two functions with different return types. It will give you the same method signature, but return the deserialized object, the headers and the status code. It does not interfere with the existing code generation and was introduced to allow situations where session data is being returned outside of the body. It will be documented further once accepted. -
3.2 - introduces support for extra elements in the pubspec, import support, arbitrary part support and a fix for arrays of date times and dates
-
3.1 - introduces support for the Kubernetes API in terms of compilation along with a considerable degree of support for the complexity of that API. It also reduces the code generated when no forms are used or forms are used but not json. It also supports the return of non-json data by just returning the string, allowing you to decode it.
-
2.9 - support inheritance using allOf where it exists. If the model from the generator provides a parentClass we modify the output to now support the correct code generation to support inheritance. Resolve issue around headers not being merged if passed by user. Fix issue with form data generation where fields need to be json encoded.
-
2.8 - resolves a number of Dart Analysis issues
-
2.6/7 - add in a new copyWith() method that allows you to make deep copies of the model and replace specific parts
-
2.5 - fixed a dangling } issue from pedantic, fixed additionalProperties support for k8s api generation, added integration tests
-
2.4 - fixed an issue if no authNames were being provided, a List<dynamic> was created instead of a List<String>
-
2.3 - this is a cleanup of the move to Dio based on pedantic feedback
-
1.5 - fixed the pubspec.yaml
-
1.4 - added in serialization of outgoing data because Dart cannot serialize an enum using json.
-
We intend to support the
oneOf
syntax for parameters for request and response types by using optional parameters. This won’t change method calls when you are only passing one type. -
We will wrap exceptions that have generated models
-
We intend to be generating server side code for supporting Dart server side applications.
-
We are considering memoization