Skip to content

Commit 8846d1b

Browse files
authored
Merge pull request #378 from microsoft/op-operations-pattern
Operations pattern
2 parents a89ccea + 875d35a commit 8846d1b

File tree

1 file changed

+111
-26
lines changed

1 file changed

+111
-26
lines changed

graph/patterns/operations.md

Lines changed: 111 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@
22

33
Microsoft Graph API Design Pattern
44

5-
*The operations pattern provides the ability to model a change that impacts multiple resources and can't be effectively modeled by using HTTP methods.*
5+
*The operations pattern provides the ability to model a change that might impact multiple resources and can't be effectively modeled by using HTTP methods.*
66

77
## Problem
88

9-
Sometimes when modeling a complex business domain, API designers need to model a business operation that effects multiple resources and needs to be performed as a single unit. Modeling the operation via HTTP methods on each individual resource might be either ineffective or not reflect how it's processed by the backend service. In addition, the operation might produce observable side effects.
9+
Sometimes when modeling a complex business domain, API designers need to model a business operation that effects one or multiple resources and has additional semantic meaning that cannot be expressed by HTTP methods. Modeling the operation via HTTP methods on each individual resource might be either inefficient or expose internal implementation details.
1010

1111
## Solution
1212

13-
To address these use cases, API designers might use operational resources such as functions or actions.
14-
If the operation doesn't have any side effects and MUST return a single instance of a type or a collection of instances, then the designer SHOULD use the OData function; otherwise, the designer can model the operation as an action.
13+
To address these use cases, API designers can use operational resources such as functions or actions. If the operation doesn't have any side effects and MUST return a single instance of a type or a collection of instances, then the designer SHOULD use OData functions; otherwise, the designer can model the operation as an action.
1514

1615
## When to use this pattern
1716

18-
The operations pattern is well suited to use cases that cannot be modeled as a single HTTP method on a resource and require either multiple round trips to complete a single logical operation or produce one or multiple side effects.
17+
The operation pattern might be justified when a modeling operation represents one or combination of the following:
18+
19+
- a change of a resource (i.e., increment the value of a property) rather than a state (i.e., the final value of the property)
20+
- complex processing logic that shouldn't be exposed to the client
21+
- operation parameters might convey a restricted set of option (i.e., a report that has to specify a date range)
22+
- the operation leverage some service-side data not exposed to (or easily retrieved in context by) the user.
1923

2024
You can consider related patterns such as [long running operations](./long-running-operations.md) and [change tracking](./change-tracking.md).
2125

2226
## Issues and considerations
2327

24-
- Microsoft Graph does NOT support unbound actions or functions. Bound actions and functions are invoked on resources matching the type of the binding parameter. The binding parameter can be of any type, and it MAY be Nullable. For Microsoft Graph, actions and functions must have the `isBound="true"` attribute. The first parameter is the binding parameter.
28+
- Microsoft Graph does NOT support unbound actions or functions. Bound actions and functions MUST must have the `isBound="true"` attribute and a binding parameter. Bound operations are invoked on resources matching the type of the binding parameter.The first parameter of a bound operation is always the binding parameter.The binding parameter can be of any type, and parameter value MAY be Nullable.
2529

2630
- Both actions and functions support overloading, meaning a schema might contain multiple actions or functions with the same name. The overload rules as per the OData [standard](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_FunctionOverloads) apply when adding parameters to actions and functions.
2731

@@ -33,32 +37,113 @@ You can consider related patterns such as [long running operations](./long-runni
3337

3438
- Microsoft Graph supports the use of optional parameters. The optional parameter annotation can be used instead of creating function or action overloads when unnecessary.
3539

36-
- API designer **MUST** use POST to call operations on resources.
40+
- API designer **MUST** use POST to call actions on resources.
41+
- API designer **MUST** use GET to call functions on resources.
42+
43+
- The addition of a new mandatory not-nullable parameter to an existing action or function is a breaking change and is not allowed without proper versioning that is in accordance with our [deprecation guidelines](https://github.com/microsoft/api-guidelines/blob/vNext/graph/deprecation.md).
3744

38-
- The addition of a new mandatory not-nullable parameter to an existing action or function is a breaking change and is not allowed without proper versioning.
45+
## Examples
3946

40-
## Example
47+
### A user wants to forward email
4148

4249
```
43-
<Action Name="createUploadSession" IsBound="true" ags:EnabledForPassthrough="true" ags:OwnerService="Microsoft.Exchange">
44-
<Parameter Name="bindingParameter" Type="Collection(graph.attachment)" />
45-
<Parameter Name="AttachmentItem" Type="graph.attachmentItem" Nullable="false" />
46-
<ReturnType Type="graph.uploadSession" />
47-
</Action>
50+
POST https://graph.microsoft.com/v1.0/me/messages/AQMkADNkMmMxYzIwLWJkOTItNDczZC1hNmYyLWUwZjk2ZTljMDQyNQBGAAAD1dY5iRo4x0_pEqop6hOrQAcAeGCrbYV1-kiG-z9Rv6yHMgAAAgEJAAAAeGCrbYV1-kiG-z9Rv6yHMgABRxeUKgAAAA==/forward
51+
52+
{
53+
"comment": "FYI",
54+
"toRecipients": [
55+
{
56+
"emailAddress": {
57+
"address": "[email protected]",
58+
"name": "Alex Darrow"
59+
}
60+
}
61+
]
62+
}
63+
```
64+
Response:
65+
```
66+
HTTP/1.1 202 Accepted
67+
68+
"cache-control": "private",
69+
"client-request-id": "ca2d0416-a2c1-05af-df60-0921547a86e9",
70+
"content-length": "0",
71+
"request-id": "8b53016f-cc2b-4d9f-9818-bd6f0a5e3cd0"
72+
```
73+
74+
`forward` operation is modeled as an asynchronous action bound to the Graph `message` entity type because the operation represents a complex business logic processed on the server side.
4875
```
49-
<Action Name="deprovision" IsBound="true" ags:OwnerService="Microsoft.Intune.Devices">
50-
<Parameter Name="bindingParameter" Type="graph.managedDevice" />
51-
<Parameter Name="deprovisionReason" Type="Edm.String" Nullable="false" Unicode="false" />
76+
<Action Name="forward" IsBound="true">
77+
<Parameter Name="bindingParameter" Type="graph.message" />
78+
<Parameter Name="ToRecipients" Type="Collection(graph.recipient)" />
79+
<Parameter Name="Message" Type="graph.message" />
80+
<Parameter Name="Comment" Type="Edm.String" Unicode="false" />
5281
</Action>
82+
```
83+
84+
### A user wants to see recent application activities
85+
86+
```
87+
GET https://graph.microsoft.com/v1.0/me/activities/recent
88+
```
89+
90+
Response:
91+
92+
```
93+
HTTP/1.1 200 OK
94+
95+
{
96+
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(userActivity)",
97+
"value": []
98+
}
99+
```
100+
`recent` function will query the most recent historyItems and then pull related activities therefore the operation represents a complex business logic processed on the server side. This operation doesn't change any server data and is a good fit for a function. The function is bound to the collection of `userActivity` entity type.
101+
102+
```
103+
<Function Name="recent" EntitySetPath="activities" IsBound="true">
104+
<Parameter Name="bindingParameter" Type="Collection(graph.userActivity)" />
105+
<ReturnType Type="Collection(graph.userActivity)" />
106+
</Function>
107+
```
108+
### Get a report that provides the number of active users using Microsoft Edge
109+
110+
```
111+
https://graph.microsoft.com/beta/reports/getBrowserUserCounts(period='D7')
112+
```
53113

54-
<Function Name="additionalAccess" IsBound="true" ags:OwnerService="Microsoft.IGAELM">
55-
<Parameter Name="bindingParameter" Type="Collection(graph.accessPackageAssignment)" />
56-
<ReturnType Type="Collection(graph.accessPackageAssignment)" />
57-
</Function>
114+
Response:
58115

59-
<Function Name="compare" IsBound="true" ags:OwnerService="Microsoft.Intune.DeviceIntent">
60-
<Parameter Name="bindingParameter" Type="graph.deviceManagementIntent" />
61-
<Parameter Name="templateId" Type="Edm.String" Unicode="false" />
62-
<ReturnType Type="Collection(graph.deviceManagementSettingComparison)" />
63-
</Function>
116+
```
117+
HTTP/1.1 200 OK
118+
Content-Type: application/json
119+
Content-Length: 205
120+
121+
{
122+
"value":[
123+
{
124+
"reportRefreshDate":"2021-04-17",
125+
"reportPeriod":7,
126+
"userCounts":[
127+
{
128+
"reportDate":"2021-04-17",
129+
"edge":413
130+
},
131+
{
132+
"reportDate":"2021-04-16",
133+
"edge":883
134+
}
135+
]
136+
}
137+
]
138+
}
139+
```
64140

141+
`getBrowserUserCounts` operation doesn't change any server data and is a good fit for a function.`period` operation parameter convey a restricted set of options representing the number of days over which the report is aggregated. The report supports only 7,30,90, or 180 days. In addition the function doesn't return a Graph resource but streams response data in JSON or CSV formats.
142+
143+
```
144+
<Function Name="getBrowserUserCounts" IsBound="true">
145+
<Parameter Name="reportRoot" Type="graph.reportRoot" />
146+
<Parameter Name="period" Type="Edm.String" Nullable="false" Unicode="false" />
147+
<ReturnType Type="Edm.Stream" Nullable="false" />
148+
</Function>
149+
```

0 commit comments

Comments
 (0)