diff --git a/graph/GuidelinesGraph.md b/graph/GuidelinesGraph.md index 1aa99b62..2afa6e77 100644 --- a/graph/GuidelinesGraph.md +++ b/graph/GuidelinesGraph.md @@ -202,13 +202,13 @@ The three most often used patterns in Microsoft Graph today are type hierarchy, - **[Enums](./patterns/enums.md)** represent a subset of the nominal type they rely on, and are especially useful in cases where certain properties have predefined, limited options. -The following table shows a summary of the main qualities for each pattern and can help you select a pattern fit for your use case. +The following table shows a summary of the main qualities for each pattern and can help you select a pattern fit for your use case. The **TypeSpec representation** column shows how each pattern is authored with the [`@microsoft/typespec-msgraph`](https://aka.ms/typespec) library; see the [facets TypeSpec example](./patterns/facets.md#facets-in-typespec) for a worked sample. -| API qualities\patterns | Properties and behavior described in metadata | Supports combinations of properties and behaviors | Simple query construction | -|-------------------------|-----------------------------------------------|---------------------------------------------------|---------------------------| -| Type hierarchy | yes | no | no | -| Facets | partially | yes | yes | -| Flat bag | no | no | yes | +| API qualities\patterns | Properties and behavior described in metadata | Supports combinations of properties and behaviors | Simple query construction | TypeSpec representation | +|-------------------------|-----------------------------------------------|---------------------------------------------------|---------------------------|-------------------------| +| Type hierarchy | yes | no | no | `extends` (with `@abstract` base) | +| Facets | partially | yes | yes | `@facet` on a nullable `@complex` property | +| Flat bag | no | no | yes | plain entity properties (no dedicated decorator) | #### Pros and cons diff --git a/graph/patterns/facets.md b/graph/patterns/facets.md index 949d573a..d69a2790 100644 --- a/graph/patterns/facets.md +++ b/graph/patterns/facets.md @@ -107,3 +107,98 @@ Response shortened for readability: } ] ``` + +## Facets in TypeSpec + +In [TypeSpec](https://aka.ms/typespec), the facets pattern is expressed with the `@facet` decorator from the `@microsoft/typespec-msgraph` library. A facet is a **nullable property** on an `@entity` model whose type is a `@complex` model. The `@facet` decorator marks the property as a variant facet so that authoring tooling and linters can validate it. + +The following TypeSpec models the same `driveItem` facets shown in the CSDL example above — each variant (`audio`, `file`, `folder`, `image`, `video`) is a complex type, and the entity carries one nullable facet property per variant: + +```typespec +// One @complex type per variant facet +@complex +model audio { + @doc("The title of the album for this audio file.") + album: string | null; +} + +@complex +model file { + @doc("The MIME type for the file.") + mimeType: string | null; +} + +@complex +model folder { + @doc("Number of children contained immediately within this container.") + childCount: int32 | null; +} + +@complex +model image { + @doc("Width of the image, in pixels.") + width: int32 | null; + + @doc("Height of the image, in pixels.") + height: int32 | null; +} + +@complex +model video { + @doc("Duration of the video, in milliseconds.") + duration: int64 | null; +} + +// The entity declares one nullable facet property per variant +@entity +model driveItem { + @key id: string; + + @doc("The name of the item (file name, folder name).") + displayName: string | null; + + @doc("Audio facet. Present when the item is an audio file.") + @facet audio: audio | null; + + @doc("File facet. Present when the item is a file.") + @facet file: file | null; + + @doc("Folder facet. Present when the item is a folder.") + @facet folder: folder | null; + + @doc("Image facet. Present when the item is an image.") + @facet image: image | null; + + @doc("Video facet. Present when the item is a video.") + @facet video: video | null; +} +``` + +### Rules for `@facet` + +The `@facet` decorator is validated by the `@microsoft/typespec-msgraph` linter: + +- The property type must be a `@complex` model — primitive, enum, and entity types are rejected. +- The property must be **nullable** (`T | null`) — a variant may be absent. +- The property must be declared on an `@entity` model — facets on `@complex` models are rejected. + +### Compiled CSDL + +`@facet` is an **authoring-time marker**: it carries no wire-format meaning, so a facet property compiles to a standard nullable complex-typed property — identical to what a hand-authored facet produces. The TypeSpec above emits: + +```xml + + + + + + + + + + + + +``` + +Because `@facet` adds no CSDL annotation, applying or omitting it produces byte-identical metadata; its value is the design intent it records and the linter checks it enables.