Find Asset Administration Shells in the Digital Twin Registry
Specification defines endpoint for retrieving shells from the Digital Twin Registry:
The endpoint /aas-api/v3/shell-descriptors
supports filtering and paging in order to give the client control over how many and which resources it wants to retrieve.
All expressions are defined using the Asset Administration Shell as a reference.
Filtering reduces the amount of retrieved shells by given criteria, paging returns a subset of the results. With sorting, the retrieved results are returned in a predefined order.
Filtering
The Digital Twin Registry API supports filtering via RQL (Resource Query Language).
Filtering of results is specified by the value of the query parameter filter
.
The general form of the query string looks as follows:
If there is an issue processing the filter expression, the response will provide details on the error.
Operators
The value for {filter expression}
is an expression that uses one of the following operators.
-
Comparison operators:
-
eq
-
in
-
ne
-
gt
-
ge
-
lt
-
le
-
like
-
likeIgnoreCase
-
-
Logical operators:
-
and
-
or
-
not
-
The following examples illustrate how an RQL {filter expression}
could look like.
Return Shells of assetKind
"INSTANCE":
eq(assetKind,"INSTANCE")
Return Shells that carry a label
named "A":
eq(labels.name,"A")
Return Shells with a given assetKind
and at least one label with name "Floor1":
and(eq(assetKind,"INSTANCE"), eq(labels.name,"Floor1"))
Return Shells with a given specificAssetIds
and(eq(specificAssetIds.name,"AssetId"), eq(specificAssetIds.value,"Floor1"))
Supported properties
Entity | Properties |
---|---|
Shell |
globalAssetId, idShort, assetType, assetKind, specificAssetIds, labels, groups |
ShellLabel |
name, shell |
ShellGroup |
name |
SpecificAssetId |
name, value, shell |
Supported operators:
-
Shell.assetType - provided value should be UTF8-BASE64-URL-encoded
-
Relation properties - are the properties used to cascade to another entity. Examples:
-
eq(shell.labels.name, "Floor1")
-
in(shell.labels.shell.groups.name, 1, 2)
-
and(eq(shell.specificAssetIds.name,"AssetId"), eq(shell.specificAssetIds.value,"Floor1"))
-
If additional properties are required, please contact us at support.semantic-stack@bosch.com.
Paging
The endpoint provides cursor pagination.
Cursor pagination
The cursor pagination methodology divides the entities of a larger dataset, based on various criteria.
-
This type of pagination is broadly intended for continuous pagination and therefore lacks the option to select a specific page index, in favor of basing the pagination on a specific cursor, provided by the back-end in the first response (assuming the dataset has more than one page).
-
In cursor pagination, once the client obtains the first page and a cursor for the next one, it can send the next request with that cursor as an argument, in order to fetch the next page.
-
Cursor pagination uses logarithmic solutions to scroll through a sorted dataset, which tends to perform increasingly better than offset pagination the larger the dataset and the closer to its end data is being fetched.
-
In other words, cursor pagination is preferable in the vast majority of use cases
One criterion to cursor pagination methodology is the size of the page, expressed as the limit
argument expressed as a query parameter (e.g., ?limit=50
).
The default and maximum page size is 500
elements. When a desired page size exceeds the maximum page size, the request will fail with an error.
Cursor pagination interaction lifecycle
This section summarizes the typical exchanges between client and server when cursor pagination is involved.
-
The client requests data via a cursor-paginating endpoint, optionally parameterizing the request with:
-
a
limit
value up to, and defaulting to500
elements -
an RQL
filter
query (defaults to "all elements of that type" if absent)
-
-
The server responds with the first page of elements.
-
If more elements are present in the dataset, the response body will contain a
nextCursor
value, expressed as a string.
-
-
If the server response contains a
nextCursor
value, the client copies it ascursor
in the query parameters of the next request -
In turn, the server provides a page of elements after that
cursor
, and again thenextCursor
value in the next response, if any more pages are available. -
This exchange iterates ad lib. until the server stops providing a
nextCursor
value in the response. -
Once no
nextCursor
value is available to the client, it "knows" it has reached the end of the desired dataset, and can stop sending further requests.
Sorting
With user-defined sorting, the client is responsible for preventing an arbitrary order of the retrieved results.
User-defined sorting can be achieved by using the RQL options operator with the keyword sort
.
Two different use cases exist:
-
Use case 1: The client provides sorting information via the
sort
keyword.-
Example:
option=sort(-id)
-
Sort direction for a property can be given with:
-
+
for ascending order -
-
for descending order
-
-
-
Use case 2: The client does not provide any sorting information.
-
The results will be sorted by default sorting.
-
Default sorting happens by ID and in ascending order, which implicitly also yields an ascending order by creation time.
-
If sorting is used with a cursor, the sort expression must NOT change from the previous request. Otherwise incorrect results or an error may occur. |
Note that:
-
User-defined sorting may result in longer response times.
-
Even if the client provides sorting information, arbitrary ordering can still occur if parallel accesses (deleting or adding elements) take place.
-
If it is important that all elements are returned, user-defined sorting cannot be used.
Currently, only reviewed attributes from the root entity can be used. If a desired attribute is not available, please contact us.
Example:
Load shells that have the label blue
assigned (filter) and sort them by idShort
.
filter=eq(labels.name, "blue")&option=sort(+idShort)
Select
The select operator trims each response down to the set of attributes defined in the arguments of the query. User-defined select can be requested via RQL for a root entity. All child entities will then not be loaded.
This means that response times can be significantly improved if only the requested information is returned.
Example:
Load only twin IDs (select) and do that only for twins that have the label blue
assigned (filter).
select=id&filter=eq(labels.name, "blue")