Enhancing API Consumption and Minimizing Network Traffic
To reduce the amount of incoming network traffic and make APIs easier to consume, use the $expand
system query option. Because API consumers request only inline representations of the related entities of query results, the returned information avoids multiple network roundtrips. Using this query option benefits metered and latency-sensitive consumers.
From APIkit for OData 1.3.0 onwards, this module supports automatic routing for ease of implementing the $expand
system query option in the most common cases. Although this feature requires more preparation and configuration, it enables the reuse of implemented flows when processing the $expand
requests.
See the OASIS specification for more information about the system query option.
Before You Begin
You must fulfill the following requirements to use the $expand
feature:
-
APIkit for OData Module (version 1.3.0)
-
A
<request-entity-collection-listener/>
implementation for each expandable entity -
Support for the
in
filter on the<request-entity-collection-listener/>
flows
$expand
Feature Example
In this example:
-
The
Employee
entity has a relatedManager
entity. -
The
Employees
entity set is a collection ofEmployee
entities. -
The
Managers
entity set is a collection ofManager
entities. -
The API location is
https://example.com/api/
.
Given this setup, the following requests retrieve employees and their managers:
-
Use
GET https://example.com/api/Employees
to retrieve a list of employees. -
Gather the
Manager
IDs through theReferentialConstraint
of their relationship. -
Use
GET https://example.com/api/Managers?$filter=ManagerID in (id1, id2, ..., idN)
to retrieve a list of related managers. -
Write a small program to merge the lists based on join criteria.
If you use the $expand
feature, the request to retrieve a list of employees with their Manager
navigation property expanded is GET https://example.com/api/Employees?$expand=Manager
.
The generic expand
Feature
Reuse existing flow implementations as a starting point for expanding requests by using the generic expand
feature, which enables you to focus on the relevant data retrieval operations while the module performs the necessary steps to ensure that the $expand
fields are complete.
An application with the generic expand
feature enabled works like any other OData Mule application. However, during the flow execution, once the module retrieves information for the main entity set, it performs additional internal requests to gather the information for any expand
field.
You can configure how the software handles errors during the expansion operation:
-
Fails the request with an error.
-
Replaces the failed expansion with a
null
value.
The generic expand
Operation
The generic expand
feature dispatches additional queries to the application when the original flow completes. Because this is done based on the application EDM
, you must make extra annotations to add enough context to the module:
-
The
EntitySet
where the expansion takes place has aNavigationPropertyBinding
for every expandableNavigationProperty
of itsEntity
.This is used to select which
<entity-collection-source/>
is executed when expanding that property. -
Each expandable
NavigationProperty
has aReferentialConstraint
attached.Internal requests use
ReferentialConstraint
when matching the value ofProperty
against the value ofReferencedProperty
.
Flow Execution
-
The main flow is executed and completed resulting in a collection of
entities
. -
The OData module gathers all the properties that need expansion.
-
For each
NavigationProperty
:-
Get the
source property
from itsReferentialConstraint
. -
Get the
referenced property
from itsReferentialConstraint
. -
Get the
destination entity set
from itsNavigationPropertyBinding
. -
For each of the
entities
get the resolvedsource property
. Add these values to asource property list
. -
Execute the internal request by invoking the
<entity-collection-source/>
fordestination entity set
with$filter=referenced property
in(…source property list)
.
-
Error Handling and Error Propagation
Error handling for OData v4 applications is local to each flow, whether you use generic expansion
or not. Error handling code for a given EntitySet
belongs to the flow implementations for that entity set, both for normal requests and for the internal requests observed during expansion processing.
Handling errors during the expansion process is not supported, because the expansion process runs after the execution of the flow finishes. There are two options available for handling errors:
-
Ignore errors during expansion: Errors during generic expansion are ignored.
By default, the expansion of collections and single objects are resolved to empty lists andnull
values respectively. -
Propagate errors during expansion: Errors arise during generic expansion.
When an error reaches the OData v4 router, the original request is answered with an error response.
You can configure error handling per-source on the Capabilities tab.
Limitations
-
Only the first
ReferentialConstraint
is considered.Navigation properties that use compound keys are not supported.
-
Expansion is done
field-by-field
instead ofEntitySet-by-EntitySet
.This can cause more internal requests than necessary.
-
The expanded entities always have an
<entity-collection-source/>
implementation.Expansion using
<entity-source/>
implementations are not executed due to performance concerns.
Implementation Guidelines
To implement the generic expansion
feature, you must annotate each source with the types that it can expand. Enabling $expand
without restrictions enables API clients to write complex queries, which can create performance issues.
If you implement $expand
manually for some relationships, leave these relationships out of the list on the Expandable Navigation Properties option. The navigation properties that don’t use the generic expansion
feature need manual implementations in the flow.
Implementation Checklist
-
Verify that your CSDL file and Mule application meet the expected requirements:
-
Every
NavigationProperty
has oneReferentialConstraint
. -
Every
EntitySet
has oneNavigationPropertyBinding
for eachNavigationProperty
of its entity type. -
Every
<entity-collection-source/>
supports thein
operator for the$filter
system query option.
-
-
For each source for which you enable
generic expand
support:-
Open the Capabilities tab.
-
Edit inline the Expandable navigation properties field.
-
Add the name of each navigation property to be expandable by using
generic expand
. -
Depending on your use case, select Ignore errors on expand to avoid errors during the generic expansion and to generate errors on the main flow.
-
-
Verify that your existing flows support the
$expand
feature.