Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions graph/GuidelinesGraph.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
95 changes: 95 additions & 0 deletions graph/patterns/facets.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<EntityType Name="driveItem">
<Key>
<PropertyRef Name="id"/>
</Key>
<Property Name="id" Type="Edm.String" Nullable="false"/>
<Property Name="displayName" Type="Edm.String" Nullable="true"/>
<Property Name="audio" Type="graph.audio" Nullable="true"/>
<Property Name="file" Type="graph.file" Nullable="true"/>
<Property Name="folder" Type="graph.folder" Nullable="true"/>
<Property Name="image" Type="graph.image" Nullable="true"/>
<Property Name="video" Type="graph.video" Nullable="true"/>
</EntityType>
```

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.