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.
Complex setup
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
Model files are importing other model files. No need to for a package import, we may just import the file itself. Instead of
import 'package:openapi/model/activity.dart';
we should have
import 'activity.dart';
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.
API file
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"
Serializers file
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.
Personal Token.
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 :)
Project Id.
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
Full Script
You can find the full script at my Github. Feel free to patch it and don't forget to Signup for future updates!
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.