From bc9abca29927336d627ec22cc219bd2cebf824f5 Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Mon, 28 Aug 2023 13:34:13 -0600 Subject: [PATCH 1/6] merge enum --- graph/patterns/enums.md | 495 +++++++++++++++++++++++++++++- graph/patterns/evolvable-enums.md | 488 ----------------------------- 2 files changed, 490 insertions(+), 493 deletions(-) delete mode 100644 graph/patterns/evolvable-enums.md diff --git a/graph/patterns/enums.md b/graph/patterns/enums.md index a47de3ea..28e356d0 100644 --- a/graph/patterns/enums.md +++ b/graph/patterns/enums.md @@ -1,4 +1,4 @@ -### Enums +# Enums 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. @@ -10,16 +10,16 @@ In OData, enums represent a subset of the nominal type they rely on, and are esp ``` -#### Pros +## Pros - 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 -#### Cons +## Cons - Adding a new value requires to go through a (generally fast) API Review - If the enum is not [evolvable](./patterns/evolvable-enums.md), adding a new value is a breaking change and will generally not be allowed -#### Enum or Booleans +## Enum or Booleans 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: @@ -100,7 +100,7 @@ but it is also open for future scenarios: Additionally speaking, depending on the situation, a nullable enum can very likely be avoided by adding a `none` member. -#### Flag Enums or Collection of Enums +## Flag Enums or Collection of Enums In case an enum can have multiple values at the same time the tentation is to model the property as a collection of Enums: @@ -127,3 +127,488 @@ However, [Flagged Enums](https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/ With such enum, customers can select multiple values in a single field: `displayMethod = tip | alert` + +## Evolvable enums + +_The evolvable enums pattern allows API producers to extend enumerated types with new members without breaking API consumers._ + +### Problem + +Frequently API producers want to add new members to an enum type after it is initially published. Some serialization libraries might fail when they encounter members in an enum type that were added after the serialization model was generated. In this documentation, we refer to any added enum members as unknown. + +### Solution + +The solution is to add a 'sentinel' member named `unknownFutureValue` at the end of the currently known enum members. The API producer then replaces any member that is numerically after `unknownFutureValue` with `unknownFutureValue`. + +If an API consumer can handle unknown enum values, the consumer can opt into receiving the unknown enum members by specifying the `Prefer: include-unknown-enum-members` HTTP header in their requests. The API producer then indicates that this preference has been applied by returning the `Preference-Applied: include-unknown-enum-members` HTTP header in the response. + +### When to use this pattern + +It is a best practice to include an `unknownFutureValue` value when the enum is initially introduced to allow flexibility to extend the enum during the lifetime of the API. Even if the API producer believes that they have included all possible members in an enum, we still strongly recommend that you include an `unknownFutureValue` member to allow for unforeseen future circumstances that may require extending the enum. + +This pattern must not be used in scenarios where an API consumer wants to use enum members that are not known to the API producer. + +### Issues and considerations + +Consider the following: + +- An enum member with the name of `unknownFutureValue` MUST only be used as a sentinel value. An API producer MUST not include a member named `unknownFutureValue` in an enum for any other purpose. + +- Changing the value (that is, position) of the `unknownFutureValue` sentinel member is considered a breaking change and must follow the [deprecation](../deprecation.md) process. + +- Enum types can have multiple members with the same numeric value to allow for aliasing enum members. `unknownFutureValue` MUST not be aliased to any other enum member. + +- There is no ability for a client to indicate that it can handle a subset of unknown enum members. Instead, they can only specify that either they cannot handle any unknown enum members or they can handle any unknown enum members. + +- The `Prefer: include-unknown-enum-members` header applies to all included enums in the request/response. There is no way for an API consumer to apply the behavior to only a subset of enum types. + +- New values MUST not be inserted into the enum before `unknownFutureValue`. Implementers are recommended to make the numeric value of `unknownFutureValue` one greater than the last known enum member to ensure that there are no gaps into which a new member could be inadvertently added. The exception to this is the case of flagged enums, in which case the value of `unknownFutureValue` should be the next power of 2 value. + +- For flagged enums, care should be exercised to ensure that `unknownFutureValue` is not included in any enum members that represent a combination of other enum members. + +- If the value of a property containing a flag enum contains multiple unknown values, they should all be replaced with a single `unknownFutureValue` value (that is, there should not be multiple `unknownFutureValue` values returned). + +- If an API consumer specifies `unknownFutureValue` for the value of a property in a `POST`/`PUT` request or as a parameter of an action or function, the API producer must reject the request with a `400 Bad Request` HTTP status. + +- If an API consumer specifies `unknownFutureValue` for the value of a property in a `PATCH` request, the API producer must treat the property as if it were absent (that is, the existing value should not be changed). In the case where the API producer treats `PATCH` as an upsert, the call MUST be rejected with a `400 Bad Request` HTTP status. + +- If an API consumer specifies an enum member greater than `unknownFutureValue` in any request without specifying the `Prefer: include-unknown-enum-members` header, the API producer must reject the request with a `400 Bad Request` HTTP status. + +- For details about how the `unknownFutureValue` value is handled as part of a `$filter` clause, consult the following examples: + + - **CSDL** + + ```xml + + + + + + + + + + + ``` + + - **Filter behavior** + + | `$filter` clause | `Prefer: include-unknown-enum-members` Absent | `Prefer: include-unknown-enum-members` Present | + | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | + | `enumProperty eq unknownFutureValue` | Return entities where enumProperty has any value greater than `unknownFutureValue` replacing actual value with `unknownFutureValue` | Return nothing | + | `enumProperty gt unknownFutureValue` | Return entities where enumProperty has any value greater than `unknownFutureValue` replacing actual value with `unknownFutureValue` | Return entities where enumProperty has any value greater than `unknownFutureValue` | + | `enumProperty lt unknownFutureValue` | Return entities where enumProperty has any known value (i.e. less than `unknownFutureValue`) | Return entities where enumProperty has any value less than `unknownFutureValue` | + | `enumProperty eq newValue` | `400 Bad Request` | Return entities where enumProperty has the value `newValue` | + | `enumProperty gt newValue` | `400 Bad Request` | Return entities where enumProperty has a value greater than `newValue` | + | `enumProperty lt newValue` | `400 Bad Request` | Return entities where enumProperty has a value less than `newValue` | + +- If an evolvable enum is included in an `$orderby` clause, the actual numeric value of the member should be used to order the collection. After sorting, the member should then be replaced with `unknownFutureValue` when the `Prefer: include-unknown-enum-members` header is absent. + +### Examples + +For the following examples, we consider the `managedDevice` entity, which refers to the `managedDeviceArchitecture` enum type. + +```xml + + + + + +``` + +When the `managedDeviceArchitecture` enum was initially published to Microsoft Graph, it was defined as follows: + +```xml + + + + + + + + + +``` + +The enum was later extended to add a new value of `quantum`, leading to the following CSDL: + +```xml + + + + + + + + + +``` + +#### Default behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture +``` + +```json +{ + "value": [ + { + "id": "0", + "displayName": "Surface Pro X", + "processorArchitecture" : "arm64" + }, + { + "id": "1", + "displayName": "Prototype", + "processorArchitecture": "unknownFutureValue" + } + { + "id": "2", + "displayName": "My Laptop", + "processorArchitecture": "x64" + } + ] +} +``` + +In this case, the value of the `processorArchitecture` property is `quantum`. However, because the client did not request the `include-unknown-enum-members` header, the value was replaced with `unknownFutureValue`. + +#### Include opt-in header + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "value": [ + { + "displayName": "Surface Pro X", + "processorArchitecture" : "arm64" + }, + { + "displayName": "Prototype", + "processorArchitecture": "quantum" + }, + { + "displayName": "My Laptop", + "processorArchitecture": "x64" + } + ] +} +``` + +#### Default sort behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$orderBy=processorArchitecture +``` + +```json +{ + "value": [ + { + "displayName": "Surface Pro X", + "processorArchitecture": "arm64" + }, + { + "displayName": "My Laptop", + "processorArchitecture": "x64" + }, + { + "displayName": "Prototype", + "processorArchitecture": "unknownFutureValue" + } + ] +} +``` + +#### Sort behavior with opt-in header + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "value": [ + { + "displayName": "Surface Pro X", + "processorArchitecture" : "arm64" + }, + { + "displayName": "My Laptop", + "processorArchitecture": "x64" + }, + { + "displayName": "Prototype", + "processorArchitecture": "quantum" + } + ] +} +``` + +#### Default filter behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 +``` + +```json +{ + "value": [ + { + "displayName": "My Laptop", + "processorArchitecture": "x64" + }, + { + "displayName": "Prototype", + "processorArchitecture": "unknownFutureValue" + } + ] +} +``` + +#### Filter behavior with opt-in header + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "value": [ + { + "displayName": "My Laptop", + "processorArchitecture": "x64" + }, + { + "displayName": "Prototype", + "processorArchitecture": "quantum" + } + ] +} +``` + +#### Patch example + +```http +PATCH https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/1 + +{ + "displayName": "Secret Prototype", + "processorArchitecture": "unknownFutureValue" +} +``` + +```json +{ + "id": "1", + "displayName": "Secret Prototype", + "processorArchitecture": "unknownFutureValue" +} +``` + +```http +GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/1 +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "id": "1", + "displayName": "Secret Prototype", + "processorArchitecture": "quantum" +} +``` + +### Flag enum examples + +For the following examples, we consider the `windowsUniversalAppX` entity, which refers to the `windowsArchitecture` flag enum type. + +```xml + + + + + +``` + +When the `windowsArchitecture` enum was initially published to Microsoft Graph, it was defined as follows: + +```xml + + + + + + + + + +``` + +The enum was later extended to add a new value of `quantum`, leading to the following CSDL: + +```xml + + + + + + + + + +``` + +### Flag enum default behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures +``` + +```json +{ + "value": [ + { + "id": "0", + "displayName": "OneNote", + "applicableArchitectures" : "neutral" + }, + { + "id": "1", + "displayName": "Minecraft", + "applicableArchitectures": "x86,x64,arm,unknownFutureValue" + } + { + "id": "2", + "displayName": "Edge", + "applicableArchitectures": "x64,arm,unknownFutureValue" + } + ] +} +``` + +In this case, the value of the `applicableArchitectures` property includes `quantum`. However, because the client did not request the `include-unknown-enum-members` header, the value was replaced with `unknownFutureValue`. + +### Flag enum include opt-in header + +```http +GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "value": [ + { + "id": "0", + "displayName": "OneNote", + "applicableArchitectures" : "neutral" + }, + { + "id": "1", + "displayName": "Minecraft", + "applicableArchitectures": "x86,x64,arm,quantum" + } + { + "id": "2", + "displayName": "Edge", + "applicableArchitectures": "x64,arm,quantum" + } + ] +} +``` + +#### Flag enum default filter behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue +``` + +```json +{ + "value": [ + { + "id": "1", + "displayName": "Minecraft", + "applicableArchitectures": "x86,x64,arm,unknownFutureValue" + } + { + "id": "2", + "displayName": "Edge", + "applicableArchitectures": "x64,arm,unknownFutureValue" + } + ] +} +``` + +#### Flag enum include opt-in header filter behavior + +```http +GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "value": [] +} +``` + +#### Flag enum patch example + +```http +PATCH https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/1 + +{ + "displayName": "Minecraft 2", + "processorArchitecture": "unknownFutureValue" +} +``` + +```json +{ + "id": "1", + "displayName": "Minecraft 2", + "applicableArchitectures": "unknownFutureValue" +} +``` + +```http +GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/1 + +Prefer: include-unknown-enum-members +``` + +```json +Preference-Applied: include-unknown-enum-members + +{ + "id": "1", + "displayName": "Minecraft 2", + "applicableArchitectures": "x86,x64,arm,quantum" +} +``` diff --git a/graph/patterns/evolvable-enums.md b/graph/patterns/evolvable-enums.md deleted file mode 100644 index 834575dc..00000000 --- a/graph/patterns/evolvable-enums.md +++ /dev/null @@ -1,488 +0,0 @@ -# Evolvable enums - -Microsoft Graph API Design Pattern - -*The evolvable enums pattern allows API producers to extend enumerated types with new members without breaking API consumers.* - -Note: You might be interested in reading the [Enum guidance](./enums.md) first - -## Problem - -Frequently API producers want to add new members to an enum type after it is initially published. Some serialization libraries might fail when they encounter members in an enum type that were added after the serialization model was generated. In this documentation, we refer to any added enum members as unknown. - -## Solution - -The solution is to add a 'sentinel' member named `unknownFutureValue` at the end of the currently known enum members. The API producer then replaces any member that is numerically after `unknownFutureValue` with `unknownFutureValue`. - -If an API consumer can handle unknown enum values, the consumer can opt into receiving the unknown enum members by specifying the `Prefer: include-unknown-enum-members` HTTP header in their requests. The API producer then indicates that this preference has been applied by returning the `Preference-Applied: include-unknown-enum-members` HTTP header in the response. - -## When to use this pattern - -It is a best practice to include an `unknownFutureValue` value when the enum is initially introduced to allow flexibility to extend the enum during the lifetime of the API. Even if the API producer believes that they have included all possible members in an enum, we still strongly recommend that you include an `unknownFutureValue` member to allow for unforeseen future circumstances that may require extending the enum. - -This pattern must not be used in scenarios where an API consumer wants to use enum members that are not known to the API producer. - -## Issues and considerations - -Consider the following: - -- An enum member with the name of `unknownFutureValue` MUST only be used as a sentinel value. An API producer MUST not include a member named `unknownFutureValue` in an enum for any other purpose. - -- Changing the value (that is, position) of the `unknownFutureValue` sentinel member is considered a breaking change and must follow the [deprecation](../deprecation.md) process. - -- Enum types can have multiple members with the same numeric value to allow for aliasing enum members. `unknownFutureValue` MUST not be aliased to any other enum member. - -- There is no ability for a client to indicate that it can handle a subset of unknown enum members. Instead, they can only specify that either they cannot handle any unknown enum members or they can handle any unknown enum members. - -- The `Prefer: include-unknown-enum-members` header applies to all included enums in the request/response. There is no way for an API consumer to apply the behavior to only a subset of enum types. - -- New values MUST not be inserted into the enum before `unknownFutureValue`. Implementers are recommended to make the numeric value of `unknownFutureValue` one greater than the last known enum member to ensure that there are no gaps into which a new member could be inadvertently added. The exception to this is the case of flagged enums, in which case the value of `unknownFutureValue` should be the next power of 2 value. - -- For flagged enums, care should be exercised to ensure that `unknownFutureValue` is not included in any enum members that represent a combination of other enum members. - -- If the value of a property containing a flag enum contains multiple unknown values, they should all be replaced with a single `unknownFutureValue` value (that is, there should not be multiple `unknownFutureValue` values returned). - -- If an API consumer specifies `unknownFutureValue` for the value of a property in a `POST`/`PUT` request or as a parameter of an action or function, the API producer must reject the request with a `400 Bad Request` HTTP status. - -- If an API consumer specifies `unknownFutureValue` for the value of a property in a `PATCH` request, the API producer must treat the property as if it were absent (that is, the existing value should not be changed). In the case where the API producer treats `PATCH` as an upsert, the call MUST be rejected with a `400 Bad Request` HTTP status. - -- If an API consumer specifies an enum member greater than `unknownFutureValue` in any request without specifying the `Prefer: include-unknown-enum-members` header, the API producer must reject the request with a `400 Bad Request` HTTP status. - -- For details about how the `unknownFutureValue` value is handled as part of a `$filter` clause, consult the following examples: - - - **CSDL** - - ```xml - - - - - - - - - - - ``` - - - **Filter behavior** - - | `$filter` clause | `Prefer: include-unknown-enum-members` Absent | `Prefer: include-unknown-enum-members` Present | - |---|---|---| - | `enumProperty eq unknownFutureValue`| Return entities where enumProperty has any value greater than `unknownFutureValue` replacing actual value with `unknownFutureValue`| Return nothing | - | `enumProperty gt unknownFutureValue`| Return entities where enumProperty has any value greater than `unknownFutureValue` replacing actual value with `unknownFutureValue` | Return entities where enumProperty has any value greater than `unknownFutureValue` | - | `enumProperty lt unknownFutureValue`| Return entities where enumProperty has any known value (i.e. less than `unknownFutureValue`) | Return entities where enumProperty has any value less than `unknownFutureValue`| - | `enumProperty eq newValue` | `400 Bad Request` | Return entities where enumProperty has the value `newValue` | - | `enumProperty gt newValue` | `400 Bad Request` | Return entities where enumProperty has a value greater than `newValue` | - | `enumProperty lt newValue` | `400 Bad Request` | Return entities where enumProperty has a value less than `newValue` | - -- If an evolvable enum is included in an `$orderby` clause, the actual numeric value of the member should be used to order the collection. After sorting, the member should then be replaced with `unknownFutureValue` when the `Prefer: include-unknown-enum-members` header is absent. - -## Examples - -For the following examples, we consider the `managedDevice` entity, which refers to the `managedDeviceArchitecture` enum type. - -```xml - - - - - -``` - -When the `managedDeviceArchitecture` enum was initially published to Microsoft Graph, it was defined as follows: - -```xml - - - - - - - - - -``` - -The enum was later extended to add a new value of `quantum`, leading to the following CSDL: - -```xml - - - - - - - - - -``` - -### Default behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture -``` - -```json -{ - "value": [ - { - "id": "0", - "displayName": "Surface Pro X", - "processorArchitecture" : "arm64" - }, - { - "id": "1", - "displayName": "Prototype", - "processorArchitecture": "unknownFutureValue" - } - { - "id": "2", - "displayName": "My Laptop", - "processorArchitecture": "x64" - } - ] -} -``` - -In this case, the value of the `processorArchitecture` property is `quantum`. However, because the client did not request the `include-unknown-enum-members` header, the value was replaced with `unknownFutureValue`. - -### Include opt-in header - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "value": [ - { - "displayName": "Surface Pro X", - "processorArchitecture" : "arm64" - }, - { - "displayName": "Prototype", - "processorArchitecture": "quantum" - }, - { - "displayName": "My Laptop", - "processorArchitecture": "x64" - } - ] -} -``` - -### Default sort behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$orderBy=processorArchitecture -``` - -```json -{ - "value": [ - { - "displayName": "Surface Pro X", - "processorArchitecture" : "arm64" - }, - { - "displayName": "My Laptop", - "processorArchitecture": "x64" - }, - { - "displayName": "Prototype", - "processorArchitecture": "unknownFutureValue" - } - ] -} -``` - -### Sort behavior with opt-in header - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "value": [ - { - "displayName": "Surface Pro X", - "processorArchitecture" : "arm64" - }, - { - "displayName": "My Laptop", - "processorArchitecture": "x64" - }, - { - "displayName": "Prototype", - "processorArchitecture": "quantum" - } - ] -} -``` - -### Default filter behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 -``` - -```json -{ - "value": [ - { - "displayName": "My Laptop", - "processorArchitecture": "x64" - }, - { - "displayName": "Prototype", - "processorArchitecture": "unknownFutureValue" - } - ] -} -``` - -### Filter behavior with opt-in header - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "value": [ - { - "displayName": "My Laptop", - "processorArchitecture": "x64" - }, - { - "displayName": "Prototype", - "processorArchitecture": "quantum" - } - ] -} -``` - -### Patch example - -```http -PATCH https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/1 - -{ - "displayName": "Secret Prototype", - "processorArchitecture": "unknownFutureValue" -} -``` - -```json -{ - "id": "1", - "displayName": "Secret Prototype", - "processorArchitecture": "unknownFutureValue" -} -``` - -```http -GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/1 -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "id": "1", - "displayName": "Secret Prototype", - "processorArchitecture": "quantum" -} -``` - -## Flag enum examples - -For the following examples, we consider the `windowsUniversalAppX` entity, which refers to the `windowsArchitecture` flag enum type. - -```xml - - - - - -``` - -When the `windowsArchitecture` enum was initially published to Microsoft Graph, it was defined as follows: - -```xml - - - - - - - - - -``` - -The enum was later extended to add a new value of `quantum`, leading to the following CSDL: - -```xml - - - - - - - - - -``` - -### Flag enum default behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures -``` - -```json -{ - "value": [ - { - "id": "0", - "displayName": "OneNote", - "applicableArchitectures" : "neutral" - }, - { - "id": "1", - "displayName": "Minecraft", - "applicableArchitectures": "x86,x64,arm,unknownFutureValue" - } - { - "id": "2", - "displayName": "Edge", - "applicableArchitectures": "x64,arm,unknownFutureValue" - } - ] -} -``` - -In this case, the value of the `applicableArchitectures` property includes `quantum`. However, because the client did not request the `include-unknown-enum-members` header, the value was replaced with `unknownFutureValue`. - -### Flag enum include opt-in header - -```http -GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "value": [ - { - "id": "0", - "displayName": "OneNote", - "applicableArchitectures" : "neutral" - }, - { - "id": "1", - "displayName": "Minecraft", - "applicableArchitectures": "x86,x64,arm,quantum" - } - { - "id": "2", - "displayName": "Edge", - "applicableArchitectures": "x64,arm,quantum" - } - ] -} -``` - -### Flag enum default filter behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue -``` - -```json -{ - "value": [ - { - "id": "1", - "displayName": "Minecraft", - "applicableArchitectures": "x86,x64,arm,unknownFutureValue" - } - { - "id": "2", - "displayName": "Edge", - "applicableArchitectures": "x64,arm,unknownFutureValue" - } - ] -} -``` - -### Flag enum include opt-in header filter behavior - -```http -GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "value": [] -} -``` - -### Flag enum patch example - -```http -PATCH https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/1 - -{ - "displayName": "Minecraft 2", - "processorArchitecture": "unknownFutureValue" -} -``` - -```json -{ - "id": "1", - "displayName": "Minecraft 2", - "applicableArchitectures": "unknownFutureValue" -} -``` - -```http -GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/1 - -Prefer: include-unknown-enum-members -``` - -```json -Preference-Applied: include-unknown-enum-members - -{ - "id": "1", - "displayName": "Minecraft 2", - "applicableArchitectures": "x86,x64,arm,quantum" -} -``` From 2ce05acc5afbe1d15b8f858f7a45f00214cdb3d0 Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Tue, 29 Aug 2023 13:04:20 -0600 Subject: [PATCH 2/6] fix codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f77559c4..17984a7e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # These are the set of folks who should review PRs on the azureRestUpdates branch. * @microsoft/azure-api-stewardship-board @Azure/api-stewardship-board -/graph/* @microsoft/graphguidelinesapprovers +/graph/ @graphguidelinesapprovers From 1d3c7e959b02d05a7710a27be8829e22c91577a7 Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Tue, 29 Aug 2023 13:04:54 -0600 Subject: [PATCH 3/6] fix codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 17984a7e..74374d71 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # These are the set of folks who should review PRs on the azureRestUpdates branch. * @microsoft/azure-api-stewardship-board @Azure/api-stewardship-board -/graph/ @graphguidelinesapprovers +/graph/ @microsoft/graphguidelinesapprovers From baf9f41ec866bc081a81f6c9bf84200699d615f9 Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Tue, 29 Aug 2023 13:06:07 -0600 Subject: [PATCH 4/6] fix codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 74374d71..8ec03f43 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # These are the set of folks who should review PRs on the azureRestUpdates branch. -* @microsoft/azure-api-stewardship-board @Azure/api-stewardship-board +/azure/ @microsoft/azure-api-stewardship-board /graph/ @microsoft/graphguidelinesapprovers From 84abd9831333a542317927c90102b1e5c605f3bb Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Tue, 29 Aug 2023 13:07:32 -0600 Subject: [PATCH 5/6] fix codeonwer --- .github/CODEOWNERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8ec03f43..d98ee4ec 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1 @@ -# These are the set of folks who should review PRs on the azureRestUpdates branch. -/azure/ @microsoft/azure-api-stewardship-board /graph/ @microsoft/graphguidelinesapprovers From 6cd4b4ff8514842f2ff2f088dec2b30f4677321a Mon Sep 17 00:00:00 2001 From: Vincenzo Chianese Date: Wed, 30 Aug 2023 13:22:12 -0600 Subject: [PATCH 6/6] use template --- graph/patterns/enums.md | 76 +++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/graph/patterns/enums.md b/graph/patterns/enums.md index 28e356d0..b674417b 100644 --- a/graph/patterns/enums.md +++ b/graph/patterns/enums.md @@ -1,25 +1,33 @@ # Enums -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. +Microsoft Graph API Design Pattern -```xml - - - - - -``` +Enums represent a subset of the nominal type they rely on, and are especially useful in cases where certain properties have predefined, limited options. + +## Problem + +The API Design requires that a specific property of a data structure has a finite and limited set of values, and such limitation needs to be clearly communicated to the user and give the developer the same structure + +## Solution + +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. + +## When to use this pattern + +Everytime a specific property of a data structure has a finite and limited set of values, and such limitation needs to be clearly communicated to the user and give the developer the same structure. + +## Issues and considerations -## Pros +### Pros - 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 -## Cons +### Cons - Adding a new value requires to go through a (generally fast) API Review - If the enum is not [evolvable](./patterns/evolvable-enums.md), adding a new value is a breaking change and will generally not be allowed -## Enum or Booleans +### Enum or Booleans 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: @@ -100,7 +108,7 @@ but it is also open for future scenarios: Additionally speaking, depending on the situation, a nullable enum can very likely be avoided by adding a `none` member. -## Flag Enums or Collection of Enums +### Flag Enums or Collection of Enums In case an enum can have multiple values at the same time the tentation is to model the property as a collection of Enums: @@ -128,27 +136,19 @@ With such enum, customers can select multiple values in a single field: `displayMethod = tip | alert` -## Evolvable enums - -_The evolvable enums pattern allows API producers to extend enumerated types with new members without breaking API consumers._ - -### Problem +### Evolvable enums Frequently API producers want to add new members to an enum type after it is initially published. Some serialization libraries might fail when they encounter members in an enum type that were added after the serialization model was generated. In this documentation, we refer to any added enum members as unknown. -### Solution - The solution is to add a 'sentinel' member named `unknownFutureValue` at the end of the currently known enum members. The API producer then replaces any member that is numerically after `unknownFutureValue` with `unknownFutureValue`. If an API consumer can handle unknown enum values, the consumer can opt into receiving the unknown enum members by specifying the `Prefer: include-unknown-enum-members` HTTP header in their requests. The API producer then indicates that this preference has been applied by returning the `Preference-Applied: include-unknown-enum-members` HTTP header in the response. -### When to use this pattern - It is a best practice to include an `unknownFutureValue` value when the enum is initially introduced to allow flexibility to extend the enum during the lifetime of the API. Even if the API producer believes that they have included all possible members in an enum, we still strongly recommend that you include an `unknownFutureValue` member to allow for unforeseen future circumstances that may require extending the enum. This pattern must not be used in scenarios where an API consumer wants to use enum members that are not known to the API producer. -### Issues and considerations +#### Considerations Consider the following: @@ -204,7 +204,17 @@ Consider the following: - If an evolvable enum is included in an `$orderby` clause, the actual numeric value of the member should be used to order the collection. After sorting, the member should then be replaced with `unknownFutureValue` when the `Prefer: include-unknown-enum-members` header is absent. -### Examples +## Example + +```xml + + + + + +``` + +### Evolveable enum examples For the following examples, we consider the `managedDevice` entity, which refers to the `managedDeviceArchitecture` enum type. @@ -244,7 +254,7 @@ The enum was later extended to add a new value of `quantum`, leading to the foll ``` -#### Default behavior +### Default behavior ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture @@ -274,7 +284,7 @@ GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=dis In this case, the value of the `processorArchitecture` property is `quantum`. However, because the client did not request the `include-unknown-enum-members` header, the value was replaced with `unknownFutureValue`. -#### Include opt-in header +### Include opt-in header ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture @@ -303,7 +313,7 @@ Preference-Applied: include-unknown-enum-members } ``` -#### Default sort behavior +### Default sort behavior ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$orderBy=processorArchitecture @@ -328,7 +338,7 @@ GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=dis } ``` -#### Sort behavior with opt-in header +### Sort behavior with opt-in header ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture @@ -357,7 +367,7 @@ Preference-Applied: include-unknown-enum-members } ``` -#### Default filter behavior +### Default filter behavior ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 @@ -378,7 +388,7 @@ GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=dis } ``` -#### Filter behavior with opt-in header +### Filter behavior with opt-in header ```http GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?$select=displayName,processorArchitecture&$filter=processorArchitecture gt x64 @@ -403,7 +413,7 @@ Preference-Applied: include-unknown-enum-members } ``` -#### Patch example +### Patch example ```http PATCH https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/1 @@ -539,7 +549,7 @@ Preference-Applied: include-unknown-enum-members } ``` -#### Flag enum default filter behavior +### Flag enum default filter behavior ```http GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue @@ -562,7 +572,7 @@ GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=disp } ``` -#### Flag enum include opt-in header filter behavior +### Flag enum include opt-in header filter behavior ```http GET https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps?$select=displayName,applicableArchitectures&$filter=applicableArchitectures has unknownFutureValue @@ -578,7 +588,7 @@ Preference-Applied: include-unknown-enum-members } ``` -#### Flag enum patch example +### Flag enum patch example ```http PATCH https://graph.microsoft.com/v1.0/deviceAppManagement/mobileApps/1