In OData, enums represent a subset of the nominal type they rely on, and are especially useful in cases where certain properties have predefined, limited options.
<EnumType Name="color">
<Member Name="Red" Value="0" />
<Member Name="Green" Value="1" />
<Member Name="Blue" Value="2" />
</EnumType>
- Our SDK generators will translate the enum to the best representation of the target programming language, resulting in a better developer experience and free client side validation
- Adding a new value requires to go through a (generally fast) API Review
- If the enum is not evolvable, adding a new value is a breaking change and will generally not be allowed
Enumerations are a good alternative to Booleans when one of the two values (true
, false
) conveys other possible values not yet conceived. Let's assume we have an publicNotification
type and a property to communicate how to display it:
<ComplexType Name="publicNotification">
<Property Name="title" Type="Edm.String" />
<Property Name="message" Type="Edm.String" />
<Property Name="displayAsTip" Type="Edm.Boolean" />
</ComplexType>
The false
value here merely communicates that the notification shall not be displayed as a tip. What if, in the future, the notification could be displayed as a tip
or alert
, and then in a more distant future, a dialog
option is viable?
With the current model, the only way is to add more boolean properties to convey the new information:
<ComplexType Name="publicNotification">
<Property Name="title" Type="Edm.String" />
<Property Name="message" Type="Edm.String" />
<Property Name="displayAsTip" Type="Edm.Boolean" />
+ <Property Name="displayAsAlert" Type="Edm.Boolean" />
+ <Property Name="displayAsDialog" Type="Edm.Boolean" />
</ComplexType>
Additionally speaking, the workload will now also have to validate the data structure and make sure that only one of the 3 values is true
By using an evolvable enum, instead, all we need to do is to add new members:
<ComplexType Name="publicNotification">
<Property Name="title" Type="Edm.String" />
<Property Name="message" Type="Edm.String" />
+ <Property Name="displayMethod" Type="microsoft.graph.displayMethod" />
- <Property Name="displayAsTip" Type="Edm.Boolean" />
- <Property Name="displayAsAlert" Type="Edm.Boolean" />
- <Property Name="displayAsDialog" Type="Edm.Boolean" />
</ComplexType>
<EnumType Name="displayMethod">
<Member Name="tip" Value="0" />
<Member Name="unknownFutureValue" Value="1" />
<Member Name="alert" Value="2" />
<Member Name="dialog" Value="3" />
</EnumType>
Similarly speaking, if you find yourself using a nullable
Enum, that is a indication that maybe what you are trying to model is something that has 3 states and an enum is more appropraite. For instance, let's assume we have a boolean property called syncEnabled
, where null
means that the value is undefined and inherited from the general tenant configuration. Instead of modelling like a boolean:
<Property Name="syncEnabled" Type="Edm.Boolean" Nullable="true"/>
An enum not only better conveys the message:
<EnumType Name="syncState">
<Member Name="enabled" Value="0" />
<Member Name="disabled" Value="1" />
<Member Name="tenantInherit" Value="2" />
<Member Name="unknownFutureValue" Value="3" />
</EnumType>
but it is also open for future scenarios:
<EnumType Name="syncState">
<Member Name="enabled" Value="0" />
<Member Name="disabled" Value="1" />
<Member Name="tenantInherit" Value="2" />
<Member Name="unknownFutureValue" Value="3" />
+ <Member Name="groupInherit" Value="4" />
</EnumType>
Additionally speaking, depending on the situation, a nullable enum can very likely be avoided by adding a none
member.
In case an enum can have multiple values at the same time the tentation is to model the property as a collection of Enums:
<Property Name="displayMethods" Type="Collection(displayMethod)"/>
However, Flagged Enums can model this use case scenario:
- <EnumType Name="displayMethod">
+ <EnumType Name="displayMethod" isFlag="true">
- <Member Name="tip" Value="0" />
+ <Member Name="tip" Value="1" />
- <Member Name="unknownFutureValue" Value="1" />
+ <Member Name="unknownFutureValue" Value="2" />
- <Member Name="alert" Value="2" />
+ <Member Name="alert" Value="4" />
- <Member Name="dialog" Value="3" />
+ <Member Name="dialog" Value="8" />
</EnumType>
With such enum, customers can select multiple values in a single field:
displayMethod = tip | alert