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 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. 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:
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
.
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.
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.
Top comments (0)