Skip to content

Commit 2938e71

Browse files
authored
Merge pull request #381 from microsoft/dm/navigationproperties
Navigation property pattern
2 parents c321118 + 1147b64 commit 2938e71

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed

graph/patterns/navigation-property.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Navigation Property
2+
3+
Microsoft Graph API Design Pattern
4+
5+
*A navigation property is used to identify a relationship between resources.*
6+
7+
## Problem
8+
--------
9+
10+
It is often valuable to represent a relationship between resources in an API.
11+
12+
Relationships between resources are often implicitly represented by a property contained in one of the resources that provides a key to a related resource. Usually that information is returned in a representation as an id value and the property is named using a convention that identifies the target type of related resource. e.g. userId
13+
14+
The use of foreign key properties to describe related resources is a weakly typed mechanism and requires additional information for a developer to traverse the relationship. Discovery of related resources is not trivial.
15+
16+
## Solution
17+
--------
18+
19+
Navigation properties are an [OData convention](https://docs.microsoft.com/en-us/odata/webapi/model-builder-untyped#navigation-property) defined in the [CSDL Specification](https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#_Toc38530365) that allows an API designer to describe a special kind of property in a model that references an related entity. In the HTTP API this property name translates to a path segment that can be appended to the URL of the primary resource in order to access a representation of the related resource. This prevents the client from needing to know any additional information on how to construct the URL to the related resource and the client does not need to retrieve the primary resource if it is only interested in the related resource. It is the responsibility of the API implementation to determine the Id of the related resource and return the representation of the related entity. For example:
20+
21+
- /user/{userId}/manager represents many-to-one relationship
22+
- /user/{userId}/messages represents one-to-many relationship
23+
24+
Additionally, using the OData Expand query parameter, related entities can be nested into the primary entity so both can be retrieved in a single round trip.
25+
26+
These relationships can be described in CSDL as follows:
27+
28+
```xml
29+
<EntityType Name="user">
30+
<NavigationProperty Name="manager" Type="user" ContainsTarget="false" >
31+
<NavigationProperty Name="messages" Type="user" ContainsTarget="true" >
32+
</EntityType>
33+
```
34+
35+
## Issues and Considerations
36+
-------------------------
37+
38+
In the current Microsoft Graph implementation, there are some limitations on the use of navigation properties that cross between backend services. These limitations are being eliminated over time, but it will be necessary to ensure support for any particular scenario. [Limitations of the current implementation](https://dev.azure.com/msazure/One/_wiki/wikis/Microsoft%20Graph%20Partners/354352/Cross-workload-navigations?anchor=supported-scenarios) are documented internally.
39+
 
40+
Navigation properties defined within an entity are not returned by default when retreiving the representation of an entity unless explicity desired by a service. The API can consumer can use the `expand` query parameterm, where supported, to retreive both the source and the target entity of the relationship in a single request.
41+
42+
Implementing support for accessing the "$ref" of a navigation property allows a caller to return just the URL of related resource. e.g. `/user/23/manager/$ref`. This is useful when a client wishes to identify the related resource but doesn't need all of its properties.
43+
44+
## When to Use this Pattern
45+
------------------------
46+
47+
### "Many-to-one" relationships
48+
49+
The use of navigation properties is preferred over including an Id field to reference the related entity in a many-to-one relationship. Id values require a client to make two round trips to retrieve the details of a related entity. With a navigation property a client can retrieve a related entity in a single round trip.
50+
51+
Many-to-one relationships are always non-contained relationships as the lifetime of the target cannot depend on the source.
52+
53+
```xml
54+
<EntityType Name="order">
55+
<NavigationProperty Name="customer" Type="customer" ContainsTarget="false" >
56+
</EntityType>
57+
```
58+
59+
60+
### "Zero-or-one-to-one" relationships
61+
62+
These navigation properties can be used as a structural organization mechanism to separate properties of an entity in a way that is similar to how complex types are often used. The primary difference being that the target of the navigation property are not returned by default when the source entity is retreived. The use of the navigation properties over complex properties is preferred when the source and target information comes from different backend APIs.
63+
64+
These relationships must be contained.
65+
66+
```xml
67+
<EntityType Name="invoice">
68+
<NavigationProperty Name="paymentDetails" Type="paymentInfo" ContainsTarget="true" >
69+
</EntityType>
70+
```
71+
72+
### "One-to-many" relationships
73+
74+
Resources that contain a parent Id property in a child resource can utilize a navigation property in the parent resource that is declared as a collection of child resources. If desirable, a parent navigation property can also be created in the child resource to the parent resource. This is usually not necessary as the parent URL is a subset of child resource URL. The main use of this would be when retrieving child resources and choosing to expand properties of the parent resource so that both can be retrieved in a single request.
75+
76+
`/invoice/{invoiceId}/items/{itemId}?expand=parentInvoice(select=invoiceDate,Customer)`
77+
78+
```xml
79+
<EntityType Name="invoice">
80+
<NavigationProperty Name="items" Type="invoiceItem" ContainsTarget="true" >
81+
</EntityType>
82+
83+
<EntityType Name="invoiceItem">
84+
<NavigationProperty Name="parentInvoice" Type="invoice" ContainsTarget="false" >
85+
</EntityType>
86+
```
87+
88+
One-to-many relationships may be contained or non-contained relations.
89+
90+
91+
## Example
92+
-------
93+
94+
### Retrieving a related entity
95+
96+
```http
97+
GET /users/{id}/manager?$select=id,displayName
98+
99+
200 OK
100+
Content-Type: application/json
101+
102+
{
103+
"id": "6b3ee805-c449-46a8-aac8-8ff9cff5d213",
104+
"displayName": "Bob Boyce"
105+
}
106+
```
107+
108+
This navigation property could be described with the following CSDL:
109+
```xml
110+
<EntityType Name="user">
111+
<NavigationProperty Name="manager" Type="graph.user" ContainsTarget="false" >
112+
</EntityType>
113+
```
114+
`ContainsTarget` is set to false for clarity, this is the default value when the attribute is omitted.
115+
### Retrieving a reference to a related entity
116+
117+
```http
118+
GET /users/{id}/manager/$ref
119+
120+
200 OK
121+
Content-Type: application/json
122+
123+
{
124+
"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/6b3ee805-c449-46a8-aac8-8ff9cff5d213/Microsoft.DirectoryServices.User"
125+
}
126+
```
127+
Note: Currently the base URL returned in $ref results are incorrect. In order to process these URLs the client will need to convert the URL to a Graph URL.
128+
129+
### Retrieving an entity with a related entity included
130+
131+
```http
132+
GET /users/{id}?select=id,displayName&expand=manager(select=id,displayName)
133+
134+
200 OK
135+
Content-Type: application/json
136+
137+
{
138+
"id": "3f057904-f936-4bf0-9fcc-c1e6f84289d8",
139+
"displayName": "Jim James",
140+
"manager": {
141+
"@odata.type": "#microsoft.graph.user",
142+
"id": "6b3ee805-c449-46a8-aac8-8ff9cff5d213",
143+
"displayName": "Bob Boyce"
144+
}
145+
}
146+
```
147+
148+
### Creating an entity with a reference to a related entity
149+
150+
Create a new user that references an existing manager
151+
```http
152+
POST /users
153+
Content-Type: application/json
154+
155+
{
156+
"displayName": "Bob",
157+
"[email protected]": "https://graph.microsoft.com/v1.0/users/{managerId}"
158+
}
159+
160+
201 Created
161+
```
162+
163+
### Updating a related entity reference
164+
165+
Update the user entity to contain a relationship to an existing manager.
166+
 
167+
```http
168+
PATCH /users/{id}
169+
Content-Type: application/json
170+
171+
{
172+
"displayName": "Bob",
173+
"[email protected]": "https://graph.microsoft.com/v1.0/users/{managerId}"
174+
}
175+
176+
204 No Content
177+
```
178+
 
179+
### Clear a related entity reference
180+
181+
Remove the relationship between the user and the manager.
182+
 
183+
```http
184+
DELETE /users/{id}/manager/$ref
185+
186+
204 No Content
187+
```
188+
189+
Delete the related entity.
190+
191+
```http
192+
DELETE /users/{id}/manager
193+
194+
204 No Content
195+
```

0 commit comments

Comments
 (0)