Safe Handling of Enums in Flutter Apps with OpenAPI Generator
Tags: flutter, openapi
Published: 2023-11-04 01:18:25

## Overview

In the development of iOS and Android apps using Flutter, the use of type-safe data structures is key to enhancing the robustness of applications. Enums are very suitable for representing a set of fixed values, but careful handling is required when integrating with API responses. In this article, I will explain how to use enums in Flutter and their caveats, and introduce how these issues can be resolved by using the [enumUnknownDefaultCase=true](https://openapi-generator.tech/docs/generators/dart-dio/) option.

## Background
- OpenAPI Version: 3.0.0
- Generator Used: dart-dio

## The Convenience and Pitfalls of Enums
Enums are extremely convenient in Flutter for managing states or handling selection options concisely. However, when enum values are closely tied to backend APIs, unexpected API responses can cause problems with enum usage.

## Inconsistency Between Enums and APIs
When API responses contain enum values, those values must match the Flutter app's enum definitions exactly. However, if the API unexpectedly returns new values, the frontend code will by default either throw an error or risk ignoring the new values.

## Problems with Dynamic Data Sets
When enum values are added on the server side, existing client apps cannot recognize new values until they are updated. This issue is especially serious in environments where the API evolves without frequent application updates.

## What is `enumUnknownDefaultCase=true`?
The OpenAPI generator has an option called [enumUnknownDefaultCase](https://openapi-generator.tech/docs/generators/dart-dio/). When set to true, it allows handling unknown enum values as a default case.

## Issues Resolved by This Option

- Backward Compatibility: Even if new enum values are added, existing applications continue to operate without crashing.
- Improved Maintainability: Changes in the API do not require frequent updates to the client.

## Sample Code
When using the OpenAPI Generator, the yaml file definition looks like this:

```yaml
components:
  schemas:
    Response:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - ACTIVE
            - INACTIVE
```

This definition, when used to generate Dart code, behaves in such a way that it throws an exception if it receives any enum values other than the specified `ACTIVE` or `INACTIVE`.

```dart
const ResponseStatusEnum _$responseStatusEnum_ACTIVE =
    const ResponseStatusEnum._('ACTIVE');
const ResponseStatusEnum _$responseStatusEnum_INACTIVE =
    const ResponseStatusEnum._('INACTIVE');

ResponseStatusEnum _$responseStatusEnumValueOf(String name) {
  switch (name) {
    case 'ACTIVE':
      return _$responseStatusEnum_ACTIVE;
    case 'INACTIVE':
      return _$responseStatusEnum_INACTIVE;
    default:
      throw new ArgumentError(name);
  }
}
```

However, setting the `enumUnknownDefaultCase=true` option includes a new item called `unknownDefaultOpenApi` in the generated code, which allows for the safe handling of unknown values in case of enum mismatches.

```dart
const ResponseStatusEnum _$responseStatusEnum_ACTIVE =
    const ResponseStatusEnum._('ACTIVE');
const ResponseStatusEnum _$responseStatusEnum_INACTIVE =
    const ResponseStatusEnum._('INACTIVE');
const ResponseStatusEnum _$responseStatusEnum_unknownDefaultOpenApi =
    const ResponseStatusEnum._('unknownDefaultOpenApi');

ResponseStatusEnum _$responseStatusEnumValueOf(String name) {
  switch (name) {
    case 'ACTIVE':
      return _$responseStatusEnum_ACTIVE;
    case 'INACTIVE':
      return _$responseStatusEnum_INACTIVE;
    case 'unknownDefaultOpenApi':
      return _$responseStatusEnum_unknownDefaultOpenApi;
    default:
      return _$responseStatusEnum_unknownDefaultOpenApi;
  }
}
```

With this behavior change, even if the API adds new enum values, the client application can handle those values as `unknownDefaultOpenApi` without needing an update. This enhances the flexibility of the app and reduces the maintenance effort.

## Conclusion
The use of enums is a very powerful tool in Flutter app development, but it is important to consider the integration with the backend. By utilizing the `enumUnknownDefaultCase=true` option, we can flexibly respond to unexpected changes in the API.