Skip to content

Commit dc6d28e

Browse files
author
Dan Kershaw [MSFT]
committed
Merge branch 'vNext' of https://github.com/microsoft/api-guidelines into dkershaw10-idempotentOperations
2 parents e2fa658 + b090216 commit dc6d28e

File tree

2 files changed

+141
-98
lines changed

2 files changed

+141
-98
lines changed

graph/patterns/dictionary.md

Lines changed: 137 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22

33
Microsoft Graph API Design Pattern
44

5-
*The dictionary type provides the ability to create a set of primitives or objects of the same type where the API consumer can define a name for each value in the set.*
5+
_The dictionary type provides the ability to create a set key/value pairs where the set of keys is dynamically specified by the API consumer._
66

77
## Problem
88

9-
The API design requires a resource to include an unknown quantity of data elements of the same type that must be named by using values provided by the API consumer.
9+
The API design requires a resource to include an unknown quantity of data values whose keys are defined by the API consumer.
1010

1111
## Solution
1212

13-
API designers use a JSON object to represent a dictionary in an `application/json` response payload. When describing the model in CSDL, a new complex type can be created that derives from `Org.OData.Core.V1.Dictionary` and then uses the `Org.OData.Validation.V1.OpenPropertyTypeConstraint` to constrain the type that can be used for the values in the dictionary.
13+
API designers use a JSON object to represent a dictionary in an `application/json` response payload. When describing the model in CSDL, a new complex type can be created that derives from `graph.Dictionary` and optionally uses the `Org.OData.Validation.V1.OpenPropertyTypeConstraint` to constrain the type that can be used for the values in the dictionary as appropriate.
1414

15-
Dictionary entries can be added via `POST`, updated via `PATCH`, and removed by setting the entry value to `null`. Multiple entries can be updated at the same time by using `PATCH` on the dictionary property.
15+
Dictionary entries can be added, removed, or modified via `PATCH` to the dictionary property. Entries are removed by setting the property to `null`.
1616

1717
## When to use this pattern
1818

1919
Before using a dictionary type in your API definition, make sure that your scenario fits the following criteria:
2020

2121
- The data values MUST be related to one another semantically as a collection.
22-
- The value types MUST be a primitive type or a **ComplexType**. Mixed primitive types are not allowed.
22+
- The values MUST be primitive or complex types.
2323
- The client MUST define the keys of this type, as opposed to the service defining them in advance.
2424

2525
### Alternatives
@@ -31,58 +31,138 @@ Before using a dictionary type in your API definition, make sure that your scena
3131

3232
Dictionaries, sometimes called maps, are a collection of name-value pairs. They allow dynamic data sets to be accessed in a systematic manner and are a good compromise between a strictly defined-ahead-of-time structure with all its named properties and a loosely defined dynamic object (such as OData OpenTypes).
3333

34-
Because dictionary entries are removed by setting the value to `null`, dictionaries can only support values that are non-nullable.
35-
36-
Open questions:
37-
38-
- Can/should PUT be supported on the dictionary property and/or the entry value?
39-
- What does OData say about being able to POST to a structured property? Will OData Web API allow that?
40-
- Must an implementer support PATCH at both the dictionary level and the entry level?
34+
Because dictionary entries are removed by setting the value to `null`, dictionaries don't support null values.
4135

4236
For more information, see the [OData reference](https://github.com/oasis-tcs/odata-vocabularies/blob/master/vocabularies/Org.OData.Core.V1.md#dictionary).
4337

4438
## Examples
4539

46-
### JSON payload example
40+
### Declaring a string dictionary
41+
The following example demonstrates defining a dictionary that can contain string values.
42+
43+
```xml
44+
<ComplexType Name="stringDictionary" BaseType="graph.Dictionary">
45+
<Annotation Term="Org.OData.Validation.V1.OpenPropertyTypeConstraint">
46+
<Collection>
47+
<String>Edm.String</String>
48+
</Collection>
49+
</Annotation>
50+
</ComplexType>
51+
```
52+
53+
### Defining a dictionary property
54+
The following example shows defining a dictionary property, "userTags", on the item entity type.
55+
56+
```xml
57+
<EntityType Name="item">
58+
...
59+
<Property Name="userTags" Type="self.stringDictionary"/>
60+
</EntityType>
61+
```
4762

48-
The following example illustrates the resulting JSON for a property of dictionary type. The parent object has been omitted for brevity.
63+
### Reading a dictionary
64+
Dictionaries are represented in JSON payloads as a JSON object, where the property names are comprised of the keys and their values are the corresponding key values.
4965

66+
The following example shows reading an item with a dictionary property named "userTags":
67+
68+
```HTTP
69+
GET /item
70+
```
71+
Response:
5072
```json
5173
{
52-
"author": {
53-
"domain": "contoso"
54-
},
55-
"maintainer": {
56-
"domain": "fabrikam"
57-
},
58-
"architect": {
59-
"domain": "adventureWorks"
74+
...
75+
"userTags":
76+
{
77+
"anniversary": "2002-05-19",
78+
"favoriteMovie": "Princess Bride"
6079
}
6180
}
6281
```
6382

64-
### HTTP calls examples
83+
### Setting a dictionary value
84+
The following example shows setting a dictionary value. If "hairColor" already exists, it is updated, otherwise it is added.
6585

66-
In this set of examples, we model a **roles** property of dictionary type on the user entity, which is exposed by the users entity set.
86+
```http
87+
PATCH /item/userTags
88+
```
89+
```json
90+
{
91+
"hairColor": "purple"
92+
}
93+
```
6794

68-
#### Get an entry from the dictionary
95+
### Deleting a dictionary value
96+
A dictionary value can be removed by setting the value to null.
97+
```http
98+
PATCH /item/userTags
99+
```
100+
```json
101+
{
102+
"hairColor": null
103+
}
104+
```
105+
106+
### Declaring a complex typed dictionary
107+
Dictionaries can also contain complex types whose values may be constrained to a particular set of complex types.
108+
109+
The following example defines a complex type **roleSettings**, an **assignedRoleGroupDictionary** that contains **roleSettings**, and an **assignedRoles** property that uses the dictionary..
110+
111+
```xml
112+
<EntityType Name="principal">
113+
...
114+
<Property Name="assignedRoles" Type="self.assignedRoleGroupDictionary">
115+
</EntityType>
116+
117+
<ComplexType Name="roleSettings">
118+
<Property Name ="domain" Type="Edm.String" Nullable="false" />
119+
</ComplexType>
120+
121+
<ComplexType Name="assignedRoleGroupDictionary" BaseType="graph.Dictionary">
122+
<!-- Note: Strongly-typed dictionary
123+
of roleSettings
124+
keyed by name of roleGroup. -->
125+
<Annotation Term="Org.OData.Validation.V1.OpenPropertyTypeConstraint">
126+
<Collection>
127+
<String>microsoft.graph.roleSettings</String>
128+
</Collection>
129+
</Annotation>
130+
</ComplexType>
131+
```
132+
133+
### Reading a entity with a complex-typed dictionary
134+
135+
The following example illustrates reading an entity containing the complex-typed dictionary "assignedRoles".
69136

70137
```HTTP
71-
GET https://graph.microsoft.com/v1.0/users/10/roles/author
138+
GET /users/10
72139
```
73140

74141
Response:
75142

76143
```json
77144
{
78-
"domain": "contoso"
145+
"id": "10",
146+
"displayName": "Jane Smith",
147+
"assignedRoles": {
148+
"author": {
149+
"domain": "contoso"
150+
},
151+
"maintainer": {
152+
"domain": "fabrikam"
153+
},
154+
"architect": {
155+
"domain": "adventureWorks"
156+
}
157+
}
79158
}
80159
```
81160

82-
#### Get the dictionary
161+
### Reading the dictionary property
162+
The following example shows getting just the "assignedRoles" dictionary property.
83163

84164
```HTTP
85-
GET https://graph.microsoft.com/v1.0/users/10/roles
165+
GET /users/10/assignedRoles
86166
```
87167

88168
Response:
@@ -101,47 +181,54 @@ Response:
101181
}
102182
```
103183

104-
#### Get the entity with the dictionary
184+
#### Reading an individual entry from the dictionary
185+
The following example shows reading a single complex-typed entry named "author" from the "assignedRoles" dictionary.
105186

106187
```HTTP
107-
GET https://graph.microsoft.com/v1.0/users/10
188+
GET /users/10/assingedRoles/author
108189
```
109190

110191
Response:
111192

112193
```json
113194
{
114-
"id": "10",
115-
"displayName": "Jane Smith",
116-
"roles": {
117-
"author": {
118-
"domain": "contoso"
119-
},
120-
"maintainer": {
121-
"domain": "fabrikam"
122-
},
123-
"architect": {
124-
"domain": "adventureWorks"
125-
}
126-
}
195+
"domain": "contoso"
127196
}
128197
```
129198

130-
#### Create an entry in the dictionary
199+
#### Setting an individual entry in the dictionary
200+
The following examples shows updating the dictionary to set the value for the "author" entry. If the "author" entry does not exists it is added with the specified values; otherwise, if the "author" entry already exists, it is updated with the specified values (unspecified values are left unchanged).
131201

132202
```HTTP
133-
POST https://graph.microsoft.com/v1.0/users/10/roles/author
134-
203+
PATCH /users/10/assignedRoles/author
204+
```
205+
```json
135206
{
136-
"domain": "contoso"
207+
"author" : {
208+
"domain": "contoso"
209+
}
137210
}
138211
```
139212

140-
#### Update the dictionary
213+
#### Deleting an individual entry from the dictionary
214+
The following example shows deleting the "author" entry by setting its value to null.
141215

142216
```HTTP
143-
PATCH https://graph.microsoft.com/v1.0/users/10/roles
217+
PATCH /users/10/assignedRoles
218+
```
219+
```json
220+
{
221+
"author": null
222+
}
223+
```
144224

225+
#### Setting multiple dictionary entries
226+
The following example sets values for the "author", "maintainer" and "viewer" entries, and removes the "architect" entry by setting it to null.
227+
228+
```HTTP
229+
PATCH /users/10/assignedRoles
230+
```
231+
```json
145232
{
146233
"author": {
147234
"domain": "contoso1"
@@ -154,49 +241,7 @@ PATCH https://graph.microsoft.com/v1.0/users/10/roles
154241
},
155242
"architect": null
156243
}
157-
```
158-
159-
> **Notes:**
160-
>
161-
> - Setting one of the keys to **null** deletes it from the dictionary.
162-
> - The domain values for the existing author and maintainer entries are updated.
163-
> - The reviewer entry is inserted in the dictionary.
164-
165-
#### Update an entry in the dictionary
166-
167-
```HTTP
168-
PATCH https://graph.microsoft.com/v1.0/users/10/roles/author
169-
170-
{
171-
"domain": "fabrikam"
172-
}
173-
```
174-
175-
#### Delete an entry from the dictionary
176-
177-
```HTTP
178-
DELETE https://graph.microsoft.com/v1.0/users/10/roles/author
179-
```
180-
181-
### CDSL example
182244

183-
The following example defines a complex type **roleSettings** as well as a dictionary of which the key will be a string and the value a **roleSettings**.
184-
185-
```xml
186-
<ComplexType Name="roleSettings">
187-
<Property Name ="domain" Type="Edm.String" Nullable="false" />
188-
</ComplexType>
189-
190-
<ComplexType Name="assignedRoleGroupDictionary" BaseType="Org.OData.Core.V1.Dictionary">
191-
<!-- Note: Strongly-typed dictionary
192-
of roleSettings
193-
keyed by name of roleGroup. -->
194-
<Annotation Term="Org.OData.Validation.V1.OpenPropertyTypeConstraint">
195-
<Collection>
196-
<String>microsoft.graph.roleSettings</String>
197-
</Collection>
198-
</Annotation>
199-
</ComplexType>
200245
```
201246

202247
## See also

graph/patterns/viewpoint.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,12 @@ GET https://graph.microsoft.com/v1.0/users/8b081ef6-4792-4def-b2c9-c363a1bf41d5/
5757
```
5858

5959
```http
60+
6061
HTTP/1.1 200 OK
6162
Content-type: application/json
63+
```
6264

65+
```
6366
{
6467
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#chats",
6568
"@odata.count": 3,
@@ -94,8 +97,6 @@ The following example shows marking a chat `viewpoint` as read for a user using
9497
```http
9598
9699
POST https://graph.microsoft.com/beta/chats/19:7d898072-792c-4006-bb10-5ca9f2590649_8ea0e38b-efb3-4757-924a-5f94061cf8c2@unq.gbl.spaces/markChatReadForUser
97-
Content-Type: application/json
98-
Content-length: 106
99100
100101
{
101102
"user": {
@@ -114,12 +115,9 @@ HTTP/1.1 204 No Content
114115

115116
The following example shows how to mark a topic with the `viewpoint` label as reviewed for a user by using the `PATCH` method (this example does not represent an actual API, but only an illustration):
116117

117-
```
118+
```http
118119
PATCH https://graph.microsoft.com/beta/sampleTopics/19:7d898072-792c-4006-bb10-5ca9f259
119120
120-
HTTP/1.1 200 OK
121-
Content-Type: application/json
122-
123121
{
124122
"title": "Announcements: Changes to PowerPoint and Word to open files faster",
125123
...

0 commit comments

Comments
 (0)