Accelerate Flutter development with OpenAPI and Dart code generation

Irina Southwell
6 min readNov 24, 2019

When it comes to handling back-end services, data and business logic that needs to surface through the UI in Flutter, standard practice is to use one of the dart packages that assists with handling REST calls, e.g. “http” package. If you wanted to make a GET request and deserialise the response it would be similar to this implementation:

However, is this the most effective way to handle REST calls in Dart? What if there was a way to generate the above client code and object models automatically? Well, thanks to OpenAPI and code generation plugins this becomes possible and in this article I will demonstrate how to do it.

The OpenAPI Specification (formerly known as Swagger Specification) is an API description format for REST APIs. An OpenAPI file allows you to describe your entire API.

Before I proceed I have to thank Richard Vowles who forked from the original OpenApi codegen plugin for Dart and improved it with some key features that were missing, as follows:

  • Support for enums
  • Enhanced support for cross-platform code generation (mobile / web)
  • Support for object equality checks

The plugin itself can be found and downloaded from here https://search.maven.org/search?q=a:openapi-dart-generator

Tutorial

In this tutorial we will go through the following steps:

  1. Identify the requirements

2. Create Open API definition yaml file

3. Generate API client code in Dart using Codegen plugin

4. Use the generated code to fetch the data and display the data on screen with Flutter

1. Requirements

Let’s imagine we are tasked with building a sample application “Counter” and are required to communicate to a simple back-end service running on port 8076. The service can do the following operations:

  • Get current counter number
  • Increase counter by specified amount and
  • Reset counter

The Flutter front-end should approximately look like this (yes, I couldn’t help a cat image) and be able to communicate to the back-end service when “add” and “reset” buttons are pressed:

Counter sample app

2. Create Open API definition yaml file to describe the back-end service operations

Make sure you are using Open API version 3.0. There are a number of open source and commercial tools you can use to help with this. Swagger Editor and Stoplight are a couple that can be used.

counter.yaml

Once you’ve created your API spec, add it to your project folder. In my project, I have a folder called “api” where I store counter.yaml that describes a ‘Counter’’ API:

3. Generate API client code in Dart using Codegen plugin

  • Install Java if you don’t have it already. Can be downloaded from here
  • Download the dart codegen plugin (current version 3.1)
  • Download OpenAPI CLI (group id: org.openapitools, current version: 4.2.1)
  • From the folder where you downloaded the above run the following command:
java -cp openapi-generator-cli-4.2.1.jar:openapi-dart-generator-3.1.jar org.openapitools.codegen.OpenAPIGenerator generate -i ../api/src/main/resources/counter.yaml — additional-properties pubName=counterapi -g dart2-api — enable-post-process-file

And watch the code generation in progress…!

Once completed you should be able to see api client code, models and pubspec.yaml file generated in the same folder:

  • Download Dart dependencies

You can see that some classes have unresolved imports, so run the following command from the same folder to get the dependencies

pub get

That was pretty easy, in 3 simple steps we have Dart client code and API models generated and ready to be used in our Flutter app.

4. Reference the generated library in the Flutter sample app

First, let’s reference the library in the Flutter sample app pubspec.yaml by providing a path to “counterapi” (directory where you generated the code from)

dependencies:flutter:sdk: flutterrxdart: 0.22.0counterapi:path: ../counter_api

Then run:

pub get 

5. Time to write some code and fetch the data!

Everything should be ready now for using the api calls in the sample app.

  • Let’s create a client proxy class which will help us to instantiate API calls in Flutter blocs. Create client.dart file and add the following code, including the path to your back-end service:
client.dart
  • Now I can create counter_bloc.dart. In this class I will take care of the business logic following BLOC pattern and write some code to make actual API calls to the “Counter” service. Since one of the requirements is to get current “counter” value, I am going to create such method. But before this let’s make sure we have an instance of the Client in the constructor of this class:
import 'package:example_mobile_client/client.dart';class CounterBloc {final Client client;//constructorCounterBloc(this.client) { }}

Now I can create the getCounter() method:

Future<Counter> getCounter() async {return client.counterServiceApi.getCounter();

}

As you can see instead of writing my own client code to deal with this GET request, I just used the generated getCounter() method. In addition to this I also get typed response, in this case — “Counter” object , so there is no need to deserialise json response. To get the counter int value we can simply do

_counter.amount

IntelliJ IDE also gives me handy hints on which object properties I can access

  • But this method doesn’t do much yet. In the next step let’s also start using streams so in the future a Flutter widget can listen to the stream events and update on the fly when the counter value changes. I will also create a couple more methods to “update the counter” and “reset the counter”.
counter_bloc.dart

6. Display the data on screen

Now I have the bloc class constructed — let’s import it and use it in a Flutter widget to stream and display data on the front-end. I can also call methods from the counter_bloc to “get”, “update” and “reset” the counter.

main.dart

For the full example please refer to the GitHub repository

It should be all set now and ready to run the app!

Run Flutter app and the back-end service example

If you like the tutorial above and would like to try the full example with our back-end server and the Flutter app you can clone this repo:

https://github.com/dart-ogurets/dart-full-api-ogurets-flutter

Follow the instructions to build and run the java server with Docker (Counter Api) and Flutter app on a mobile device.

Conclusion

You maybe wondering if you should be using OpenAPI contracts and code generation plugins with Flutter. If you think one of the below points applies to you, it’s likely that you will benefit from using it:

  • You are trying to develop a complex app with Flutter and you have a bunch of microservices to talk to
  • You realised that supporting all those “get” and “post” requests and writing your own json serializers/deserializers is fragile, risky and becoming a high maintenance task
  • Inconsistent API server or client code in different applications across your tech stack and you are not sure where the source of truth is
  • In test automation: You are testing back-end services or using them to create test data for your Flutter app. Writing your own API client libraries to handle HTTP requests may become a high maintenance task

--

--

Irina Southwell

Software engineer | Founder at FeatureHub.io | Open Source — Flutter — DevOps — Test Automation