The Best Way To Consume APIs In Your Apps!

Flutter category image

Introduction

When consuming large REST APIs, it requires writing a lot of boilerplate code to support all required endpoints. To make your life easier, you can use generators to automatically create type-safe production code for your apps. I’ll show you how to do this in this article. All it takes are 5 minutes of setup and you can enjoy the best way to consume APIs in your apps.


Requirements

This approach only works if the API source offers an open API specification file to generate the code. It can be either in json or yaml format and is usually available for download in the documentation of the API.


Generators

Open API generators are available for many programming languages. In this example, we’ll focus on Dart code. You need the packages openapi_generator and openapi_generator_annotations

YAML
dependencies:
  openapi_generator_annotations: ^latest

dev_dependencies:
  openapi_generator: ^latest

Under the hood, these tools use the openapi-generator base library written in Java. If you develop for Android, chances are high that it is already installed on your system. Otherwise, you have to install it.


Generating API packages

The generator parses the specification file and creates a package to consume the api. You can store this in your project, on GitHub, or even on pub.dev or your own package repository to reuse.

Instructions for the generator are supplied via annotations. Here is an example:

Dart
import 'package:openapi_generator_annotations/openapi_generator_annotations.dart';

@Openapi(
  additionalProperties: AdditionalProperties(pubName: "park_api", ),
  inputSpec: InputSpec(path: "lib/api/specs/document.json"),
  generatorName: Generator.dart,
  outputDirectory: 'packages/park_api',
)
class ParkApiExample {}

This is a minimal form but there are many more options to configure the generator.

  • pubName is the name of the generated package
  • The InputSpec path tells the generator where it can find the specification file. There is also a RemoteSpec object which accepts a URL path.
  • generatorName defines what underlying library is used for HTTP requests. In Dart, you change choose between http (Generator.dart) and dio (Generator.dio).
  • With the outputDirectory you can specify where to put the generated files.

You can put this file anywhere and also include multiple specifications in it.

To create the package, run the build runner:

Bash
dart run build_runner build --delete-conflicting-outputs

After some seconds, new packages should appear in your project folder.

Generated packages of the openapi_generator in a Flutter app
Generated packages of the openapi_generator in a Flutter app

Have a look at the generated model classes for one of my APIs. It’s a massive list and it would take you a while to type that stuff 😉

List of created model classes of a generated API package
List of created model classes of a generated API package

The next step is to find out how we can use the package in our app.


Using generated packages

To use the package, you need to import it in your pubspec.yaml first.

Example of how to import the created packages in a Flutter app
Example of how to import the created packages in a Flutter app

In my case, I created a bunch of packages for different APIs and included them all.

To access the endpoints, you need to create an instance of DefaultApi which contains all endpoints as methods. You can then work with the API in a type-safe and object-oriented way rather than composing requests and parsing responses manually.

Intellisense auto-completion shows all available endpoints for a given API in VSCode
Intellisense auto-completion shows all available endpoints for a given API in VSCode

This approach saves you time, you’ll have fewer bugs, and the development feels easier overall. Code generators are a life-saving tool in that case as you have seen.


Dealing with code errors

The Open API Specification is quite complex to support many use cases. It is possible that the generator will create invalid code in some cases. Sometimes, it is because the API spec has a problem and sometimes, the generator doesn’t support this case yet.

Example of a code generation error of the openapi_generator package for an API
Example of a code generation error of the openapi_generator package for an API

If you encounter a problem, you have a few options here:

  • Fix the generated code manually. This is probably the fastest approach but you have to do it every time when you rerun the generator!
  • Ask the API maintainer to investigate. It can happen that a declaration is missing in the code which leads to the invalid generation.
  • Open a bug in the OpenAPI Tools GitHub repo or look for possible workarounds. Filing a bug is the most time-consuming approach.

Conclusion

For large APIs, generating the code from a specification is the best way APIs in your apps. Don’t waste time writing requests and parsing responses manually. Go the type-safe way and skip the part of writing boilerplate code. Let code generators do the heavy lifting for you!


Want More Flutter Content?

Join my bi-weekly newsletter that delivers small Flutter portions right in your inbox. A title, an abstract, a link, and you decide if you want to dive in!

Flutter ❤️ Firebase

Get started with Firebase and learn how to use it in your Flutter apps. My detailed ebook delivers you everything you need to know! Flutter and Firebase are a perfect match!

Become A Testing Expert!

Become a proficient Flutter app tester with my detailed guide. This ebook covers everything from unit tests over widget tests up to dependency mocking.