|
| 1 | +# Filter as segment |
| 2 | + |
| 3 | +There is an [OData feature](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_AddressingaSubsetofaCollection) which allows having a `$filter` in a URL segment. |
| 4 | +This feature is useful whenever there are operations on a collection and the client wants to perform those operations on a *subset* of the collection. |
| 5 | +For example, the `riskyUsers` API on Microsoft Graph has an action defined to let clients "dismiss" risky users (i.e. consider those users "not risky"): |
| 6 | + |
| 7 | +```xml |
| 8 | +<Action Name="dismiss" IsBound="true"> |
| 9 | + <Parameter Name="bindingParameter" Type="Collection(microsoft.graph.riskyUser)" /> |
| 10 | + <Parameter Name="userIds" Type="Collection(Edm.String)" /> |
| 11 | +</Action> |
| 12 | +``` |
| 13 | + |
| 14 | +Using this action, clients can call |
| 15 | + |
| 16 | +```http |
| 17 | +POST /identityProtection/riskyUsers/dismiss |
| 18 | +{ |
| 19 | + "userIds": [ |
| 20 | + "{userId1}", |
| 21 | + "{userId2}", |
| 22 | + ... |
| 23 | + ] |
| 24 | +} |
| 25 | +``` |
| 26 | + |
| 27 | +in order to dismiss the risky users with the provided IDs. Using the filter-as-segment OData feature, the action could instead be defined as: |
| 28 | + |
| 29 | +```xml |
| 30 | +<Action Name="dismiss" IsBound="true"> |
| 31 | + <Parameter Name="bindingParameter" Type="Collection(self.riskyUser)" /> |
| 32 | +</Action> |
| 33 | +``` |
| 34 | + |
| 35 | +and clients could call |
| 36 | + |
| 37 | +```http |
| 38 | +POST /identityProtection/riskyUsers/$filter=@f/dismiss?@f=id IN ('{userId1}','{userId2}',...) |
| 39 | +``` |
| 40 | + |
| 41 | +Doing this is beneficial due to the robust nature of OData filter expressions: clients will be able to dismiss risky users based on any supported filter without the service team needing to implement a new `dismiss` overload that filters based on the new criteria. |
| 42 | +However, there are some concerns about the discoverability of using the filter-as-segment feature, as well as the support of [parameter aliasing](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_ParameterAliases) that's required. |
| 43 | +As a result, functions should be introduced that act in the same way as the filter-as-segment: |
| 44 | + |
| 45 | +```xml |
| 46 | +<Function Name="filter" IsBound="true" IsComposable="true"> |
| 47 | + <Parameter Name="bindingParameter" Type="Collection(microsoft.graph.riskyUser)" Nullable="false" /> |
| 48 | + <Parameter Name="expression" Type="Edm.String" Nullable="false" /> |
| 49 | + <ReturnType Type="Collection(microsoft.graph.riskyUser)" /> |
| 50 | +</Function> |
| 51 | +``` |
| 52 | + |
| 53 | +Clients would now be able to call |
| 54 | + |
| 55 | +```http |
| 56 | +POST /identityProtection/riskyUsers/filter(expression='id IN (''{userId1}'',''{userId2}'',...)')/dismiss |
| 57 | +``` |
| 58 | + |
| 59 | +NOTE: the `'` literal in the filter expression must be escaped with `''` |
| 60 | + |
| 61 | +An example implementation of a filter function using OData WebApi can be found [here](https://github.com/OData/AspNetCoreOData/commit/7732f7e6b812d9a79a73529562f2e74b68e2794f). |
0 commit comments