Hi! We are using openapi generation for dart files to work with backend. And we experience the following issues:
- Generator setup for new people is complex
- We have to download the spec manually
- The generated code contains import errors
- The generated code is not formatted properly
In this article you will find out how we resolved the problem and even get a script which resolve all the issues.
Generation requires at least 2 files: a generator jar(or cli installed via npm) and openapi.yaml. You also need to know the syntax of an openapi generator. We don't want that to be the focus of our developers. So I started to write the script which would help with that:
#!/bin/bash FILE="`pwd`/openapi-generator-cli-4.3.1.jar" if [ -f "$FILE" ]; then echo "$FILE exists." else echo "openapi-generator-cli-4.3.1.jar file not found, downloading..." curl "https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/4.3.1/openapi-generator-cli-4.3.1.jar" --output "$FILE" fi java -jar "`pwd`/openapi-generator-cli-4.3.1.jar" generate -i "$BASE_PATH/openapi.yaml" -g dart-dio -o "$BASE_PATH/newversion"
The script checks if the jar file is downloaded and downloads it from maven repo if it is not there. Then the generation itself is launched with the '-o' argument pointing to the output folder.
Errors in generated code.
The generated code uses 'package:openapi' imports inside the generated code. This is wrong. The relative imports should be used instead. There are 3 groups of files which require slight modifications.
- Model files
- default_api.dart file
- serializers.dart file
Model files are importing other model files. No need to for a package import, we may just import the file itself. Instead of
we should have
Let's patch it. We need to iterate over the files in the 'model' folder and replace the imports:
for i in $(ls); do sed -e 's/package:openapi\/model\///g' "$GENERATED_MODEL_PATH/$i" > $TMP && mv $TMP "$BASE_MODEL_PATH/$i" flutter format "$BASE_MODEL_PATH/$i" done
We are not using '-i' option of sed as it is not working on Unix systems and go against it's phylosophy. We also format the file right away.
The default_api also uses the model files but it is placed in api folder. Let's patch it as well:
sed -e 's/package:openapi\/model\//..\/model\//g' "$GENERATED_PATH/api/default_api.dart" > $TMP && mv $TMP "$BASE_PATH/api/default_api.dart"
The serializers.dart file is placed in the root folder. So are fixing imports for it:
sed -e 's/package:openapi\/model\//model\//g' "$GENERATED_PATH/serializers.dart" > $TMP && mv $TMP "$BASE_PATH/serializers.dart"
Avoid manual download of openapi specification with Gitlab
We can also avoid downloading the specification manually and automate it as well. We need a personal token and project id of the backend repository our spec is corresponding to. Then we just make a curl request.
Open your profile:
And choose Access Tokens in the left menu. You will be able to create a new access token. Don't forget to right it down as you will see it only once in Gitlab :)
It is written in the header of the repository:
Now we can make an appropriate call:
curl -XGET --header "PRIVATE-TOKEN: YOUR-TOKEN” "https://gitlab.com/api/v4/projects/$2/repository/files/api%2fopenapi.yaml/raw?ref=master" > "$BASE_PATH/openapi.yaml"
Please, pay attention to url encoding of the file path('/' -> '%2f').
Build_runner & Cleanup
If you are using Dio you need to generate the *.g.dart files as well:
echo "generating build_value..." flutter pub run build_runner build
Now we can clean the temporary files.
echo "Removing temporary files" cd "$BASE_PATH" rm -rf ./newversion
P.S. if you don't like this apporach our EPAM folks created a package to do the similiar thing with swagger files, chopper and json_serializable.