Effective Software Development using OpenAPI Generator Part 2
Apexive is a boutique software studio that builds tech products for startups in record time using the latest tech stacks.
Table of content
In the previous article, we covered the basics of working with OpenAPI generator to simplify the process of integrating APIs into front-end code.
This article aims to take it a step ahead by using OpenAPI Repository Annotations to simplify the process further. The idea behind creating this generator is to reduce the boilerplate code involved in setting up repositories, ListBlocs, etc., that use the generated openAPI code.
The Objective
Picking up from the previous article, we already have a basic setup for our generated client-side code in a package called `openapi`. To effectively use the generated code, we have to create our own Data repositories, Filters, ListBlocs, etc.
Recommended reading: Effective Software Development using OpenAPI Generator Part 2
But this process is repetitive and cumbersome. We also have to manually rewrite the code every time the API changes and the client-side code is generated. Besides, every time we write code, we run the risk of injecting new bugs into the system, which adds additional technical and monetary costs to our process.
While using the OpenAPI generator across several projects, we saw that the process of writing the Blocs, repositories, and filters, always followed the same pattern. We quickly set out to create our code generator that let us auto-generate the Blocs and Repositories. It saves us a lot of time and manual effort.
Setup
Generate OpenAPI Client side code
Follow steps from Effective Software Development using OpenAPI Generator Part 1 to generate the client side code to a flutter project called `openapi`
Create new Flutter App
We also need a base project, which can use the generated `openapi` dart project and connect to the `petstore_api` server.
1. Create a new flutter project using
2. In the `pubspec.yaml` for `petstore_app` add the following dependencies
3. Add the following to `dev_dependencies`
4. Run `flutter packages get` to fetch all dependencies.
Usage
The primary focus of this article is to demonstrate how we utilize the power of code generation to replace manual effort. In this particular use case, we are using the following code generators:
1. `freezed`: Generates freezed classes that act as data classes for Filters used in the API. Coupled with the json_serializable generator, it provides powerful JSON serialization/deserialization capabilities.
2. `openapi_repository`: Generates the ApiRepository, ListBlocs, DataBlocs, Filters, and Repositories.
Creating the data layer
Inside `lib` create a folder called `data` and add a file called `api_repository.dart` inside it.
Inside `api_repository.dart` add the following code block:
The core part to note here is the `@OpenapiRepository` annotation which tells the @OpenapiRepository which parts it needs to build.
- `buildFor`: The OpenAPI client for which the repository needs to be generated.
- `builderList`: Specify here which methods/classes need to be used/ignored for generation.
- `dioInterceptor`: A custom DioInterceptor instance
Generating the code
flutter packages run build_runner build --delete-conflicting-outputs
This will generate the following files in the same directory:
- api_repository.freezed.dart
- api_repository.g.dart
- api_repository.openapi.dart
api_repository.openapi.dart
This file contains the core files generated by the annotation.
ApiRepository
The `ApiRepository` class is generated with the parameters passed on to the annotation. This is modeled as a singleton instance which can be used to access the generated openAPI client code.
Data/List BLoCs
DataBlocs or ListBlocs are generated for each endpoint and operation, making it easier to call the API and maintain the state.
As an example for the /pets/:id GET endpoint, the following code blocks are generated
PetFilters
Filter classes are created for each operation that takes path or query parameters. This helps define a type-safe mechanism to pass parameters to the API in a single object, improving readability and reusability.
In this example, the filter class only has one parameter called petId for the filter:
PetRepository
The repository classes for the base of the data layer as this is where different operations like read, create, update, delete, etc, are defined. The repository talks to the generated client side code in `openapi` through the `ApiRepository` singleton defined above.
The different operations in the Repository are defined based on the endpoints. If some endpoints or operations are ignored in the `@OpenapiRepository` annotation, those operations won't be generated here.
PetDataBloc
This is the Bloc layer which is the middleman between the presentation and data layer. Updates to the data in the Bloc will trigger UI updates in the presentation layer.
Similar to the Repository, the code is generated only for the allowed operations and endpoints:
Integration
Once we have all the boilerplate code out of our way, implementing the front end logic is very straight forward:
Do have a look at our example project using this generator to have a better idea about the process.
Conclusion
We’ve learned what is OpenAPI Generator, what are the most effective ways to use OpenAPI Generator and how we can simplify development even more by using OpenAPI Repository Annotations.
I hope this article was useful to you and if you enjoyed it don't forget to share it.
At Apexive, we are on the lookout for talented engineers and technical people to help us build the amazing products for the startups! If you are interested in finding out more, check out our career page Careers at Apexive.