Skip to content

Commit 1f2c06a

Browse files
committed
Provide a simpler example of a primitive dictionary before dictionary of complex type.
Provide separate examples for defining a dictionary, using the dictionary in a type definition, and then querying/adding/updating/removing dictionary entries.
1 parent bae0b0e commit 1f2c06a

File tree

1 file changed

+135
-101
lines changed

1 file changed

+135
-101
lines changed

graph/patterns/dictionary.md

Lines changed: 135 additions & 101 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 as appropriate.
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 values can be added, removed, or modified via `PATCH` to the dictionary property. Values are removed by setting the property to `null`.
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,81 +31,111 @@ 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-
- Must an implementer support PATCH at both the dictionary level and the entry level?
40-
- Should we also allow DELETE to a property to be equivalent to setting to null?
41-
- Why do we not allow mixed primitives or mixed primitive/complex typed values? what about collections?
34+
Because dictionary entries are removed by setting the value to `null`, dictionaries don't support null values.
4235

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

4538
## Examples
4639

47-
### JSON payload example
40+
### Declaring a string dictionary
41+
The following example demonstrates defining a dictionary that can contain string values.
4842

49-
The following example illustrates the resulting JSON for a property of dictionary type. The parent object has been omitted for brevity.
50-
51-
```json
52-
{
53-
"author": {
54-
"domain": "contoso"
55-
},
56-
"maintainer": {
57-
"domain": "fabrikam"
58-
},
59-
"architect": {
60-
"domain": "adventureWorks"
61-
}
62-
}
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>
6351
```
6452

65-
### HTTP calls examples
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+
```
6662

67-
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.
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.
6865

69-
#### Get an entry from the dictionary
66+
The following example shows reading an item with a dictionary property named "userTags":
7067

7168
```HTTP
72-
GET https://graph.microsoft.com/v1.0/users/10/roles/author
69+
GET /item
7370
```
74-
7571
Response:
76-
7772
```json
7873
{
79-
"domain": "contoso"
74+
...
75+
"userTags":
76+
{
77+
"anniversary": "2002-05-19",
78+
"favoriteMovie": "Princess Bride"
79+
}
8080
}
8181
```
8282

83-
#### Get the dictionary
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.
8485

85-
```HTTP
86-
GET https://graph.microsoft.com/v1.0/users/10/roles
86+
```http
87+
PATCH /item/userTags
88+
```
89+
```json
90+
{
91+
"hairColor": "purple"
92+
}
8793
```
8894

89-
Response:
90-
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+
```
91100
```json
92101
{
93-
"author": {
94-
"domain": "contoso"
95-
},
96-
"maintainer": {
97-
"domain": "fabrikam"
98-
},
99-
"architect": {
100-
"domain": "adventureWorks"
101-
}
102+
"hairColor": null
102103
}
103104
```
104105

105-
#### Get the entity with the dictionary
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".
106136

107137
```HTTP
108-
GET https://graph.microsoft.com/v1.0/users/10
138+
GET /users/10
109139
```
110140

111141
Response:
@@ -114,7 +144,7 @@ Response:
114144
{
115145
"id": "10",
116146
"displayName": "Jane Smith",
117-
"roles": {
147+
"assignedRoles": {
118148
"author": {
119149
"domain": "contoso"
120150
},
@@ -128,85 +158,89 @@ Response:
128158
}
129159
```
130160

131-
#### Create an entry in the dictionary
161+
### Reading the dictionary property
162+
The following example shows getting just the "assignedRoles" dictionary property.
132163

133164
```HTTP
134-
PATCH https://graph.microsoft.com/v1.0/users/10/roles/author
135-
136-
{
137-
"domain": "contoso"
138-
}
165+
GET /users/10/assignedRoles
139166
```
140167

141-
#### Update the dictionary
142-
143-
```HTTP
144-
PATCH https://graph.microsoft.com/v1.0/users/10/roles
168+
Response:
145169

170+
```json
146171
{
147172
"author": {
148-
"domain": "contoso1"
173+
"domain": "contoso"
149174
},
150175
"maintainer": {
151-
"domain": "fabrikam1"
152-
},
153-
"reviewer": {
154176
"domain": "fabrikam"
155177
},
156-
"architect": null
178+
"architect": {
179+
"domain": "adventureWorks"
180+
}
157181
}
158182
```
159183

160-
> **Notes:**
161-
>
162-
> - Setting one of the keys to **null** deletes it from the dictionary.
163-
> - The domain values for the existing author and maintainer entries are updated.
164-
> - The reviewer entry is inserted in the dictionary.
165-
166-
#### Update an entry in 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.
167186

168187
```HTTP
169-
PATCH https://graph.microsoft.com/v1.0/users/10/roles/author
188+
GET /users/10/assingedRoles/author
189+
```
170190

191+
Response:
192+
193+
```json
171194
{
172-
"domain": "fabrikam"
195+
"domain": "contoso"
173196
}
174197
```
175198

176-
#### Delete an entry from 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).
177201

178202
```HTTP
179-
PATCH https://graph.microsoft.com/v1.0/users/10/roles/author
203+
PATCH /users/10/assignedRoles/author
204+
```
205+
```json
180206
{
181-
"domain": null
207+
"author" : {
208+
"domain": "contoso"
209+
}
182210
}
183211
```
184212

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

187-
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**.
216+
```HTTP
217+
PATCH /users/10/assignedRoles
218+
```
219+
```json
220+
{
221+
"author": null
222+
}
223+
```
188224

189-
```xml
190-
<ComplexType Name="roleSettings">
191-
<Property Name ="domain" Type="Edm.String" Nullable="false" />
192-
</ComplexType>
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.
193227

194-
<ComplexType Name="assignedRoleGroupDictionary" BaseType="Org.OData.Core.V1.Dictionary">
195-
<!-- Note: Strongly-typed dictionary
196-
of roleSettings
197-
keyed by name of roleGroup. -->
198-
<Annotation Term="Org.OData.Validation.V1.OpenPropertyTypeConstraint">
199-
<Collection>
200-
<String>microsoft.graph.roleSettings</String>
201-
</Collection>
202-
</Annotation>
203-
<Annotation Term="SupportedHttpMethod">
204-
<Collection><!-- use this annotation to indicate you want the SDKs to generate additional request builders to update the dictionary automatically -->
205-
<String>GET</String>
206-
<String>PATCH</String>
207-
<Collection>
208-
</Annotation>
209-
</ComplexType>
228+
```HTTP
229+
PATCH /users/10/assignedRoles
230+
```
231+
```json
232+
{
233+
"author": {
234+
"domain": "contoso1"
235+
},
236+
"maintainer": {
237+
"domain": "fabrikam1"
238+
},
239+
"reviewer": {
240+
"domain": "fabrikam"
241+
},
242+
"architect": null
243+
}
210244
```
211245

212246
## See also

0 commit comments

Comments
 (0)