Skip to main content

Query Parameters

In nodeblocks, endpoints for retrieving lists of resources follow an interface defined by the Microsoft RESTful API guidelines. You can use options such as Filter, OrderBy, Pagination, Expand, Apply and so forth in the query parameters.

This document outlines the use of these parameters.

Filtering

The $filter query parameter is used to filter the retrieved resource list.

GET /resources?$filter={Filter conditions}

Filter conditions are specified as a formula comprised of resource properties and relative operators (eq, ne, gt, ge, lt, le). When combining multiple conditions, and and or can be used.

GET /orders?$filter=status eq 'completed' and totalPrice gt 100

Sorting

The $orderby query parameter is used to sort the retrieved resource list.

To sort by a specific property in ascending or descending order, use the following:

GET /resources?$orderby={Property} {asc/desc}

ascmeans ascending, while desc means descending.

GET /orders?$orderby=createdAt desc

Pagination

Our endpoints support two forms of pagination:

Skip-based pagination

This uses $skip and $top query parameters to achieve pagination of results.

$skip sets the amount of resources to skip in the list. $top sets the count of resources to return for this request..

GET /orders?$skip=10&$top=20

Cursor-based pagination

Cursor-based pagination is a method of retrieving resources before and after a specific resource (the cursor) in a list. Compared to offset/skip-based pagination, this allows for greater performance and stability on large data sets.

GET /resources?$nextToken={Cursor}&$top=10

Comparison

Pagination typeSkip-basedCursor-based
MeritsEasy to implementHigh performance even on large data sets
Allows for direct access to specific pagesUnlikely to result in duplicates or data loss across multiple pages
Stable even when data is constantly changing/added/deleted
DemeritsDecreased performance on large data setsDifficult to jump to a specific page
Chances of duplicates or missing data when navigating between pagesSlightly complicated to implement

Which type of pagination to choose depends upon project requirements and data set size. Huge data sets, or cases where resources are constantly added or removed are suited for use with Cursor-based pagination. On the other hand, if easy development or the need to jump to specific pages are an important requirement, then skip-based pagination is appropriate.

Expansion

The $expand query parameter is part of the OData protocol, and is a means to fetch related resources in a request. Normally, APIs will only return the requested resources’ properties and links to other related resources, but when $expand is used, the related resources can be fetched all at once.

For example, the Catalog service contains information about Organizations related to each product. Normally, when requesting the Product resource, links to their Organizations would be contained in the response, but not the Organization’s details themselves. Using the $expand query parameter, you can request that this data is included in the response.

GET /products?$expand=organizations

Using $expand, the client is able to retrieve all the data it needs in a single request, which improves the efficiency of the API. However, if a large amount of data is requested at once, it may affect performance. As such, it is important to combine this with the use of pagination.

Please confirm on each endpoint as to their level of support for Expand.

Apply (Transformation)

The $apply query parameter is used to apply transformations to the retrieved resource list. This is part of the OData protocol, and is used to perform operations such as aggregation, grouping, as well as support for some filtering and limiting of results. Transformations are operations that change the structure of the resulting data. Generally, these operations will change the output row count of the endpoint.

For example, when using the Catalog service, you can use $apply to calculate the total and average price of all products:

GET /products/:productId/variants?$apply=aggregate(price.amount with sum as totalPrice, price.amount with average as avgPrice)

// Response structure

{
"total": 1,
"count": 1,
"value": [
{
"totalPrice": 1000,
"avgPrice": 100
}
]
}

Multiple transformations can be used by applying then as a separator:

GET /products/:productId/variants?$apply=aggregate(price.amount with sum as totalPrice, price.amount with average as avgPrice) then filter(totalPrice gt 500)

Transformations: Aggregate

The aggregate transformation is used to calculate the sum, average, minimum, maximum, or distinct count of a property across all resources. It is formatted as the following.

aggregate({Property} with {Function} as {Alias})

Function can be one of the following:

  • sum (returns the total sum of a numeric field)
  • average (returns the average of a numeric field)
  • min (returns the minimum value of a numeric or date field)
  • max (returns the maximum value of a numeric or date field)
  • countdistinct (returns the count of unique values of a field)

In addition to the above, the $count function can be used to count the total number of resources in the result set. This function does not require a property, and is used as follows:

aggregate($count as {Alias})

Multiple properties can be aggregated as once, separated by commas. Property can be a path to a hierarchical element. As a general rule, aggregate will always return a single row of data with the calculated values.

Usage Example:

GET /products/:productId/variants?$apply=aggregate(price.amount with sum as totalPrice, price.amount with average as avgPrice, $count as variantCount)

Transformations: GroupBy

The groupby transformation is used to group resources by a property, and then perform transformations (most commonly aggregate) on the grouped resources. It is formatted as the following:

groupby(({Property1}, {Property2}, ...), {Transformation})

When used without a transformation, it will simply group the given fields by the specified properties:

GET /products?$apply=groupby((organizationId))

// Response
{
"total": 2,
"count": 2,
"value": [
{
"organizationId": "org1",
},
{
"organizationId": "org2",
},
...
]
}

When used with a transformation, it will group the given fields by the specified properties, and then apply the transformation to the grouped resources:

GET /products?$apply=groupby((organizationId), aggregate($count as productCount))

// Response
{
"total": 2,
"count": 2,
"value": [
{
"organizationId": "org1",
"productCount": 5
},
{
"organizationId": "org2",
"productCount": 10
},
...
]
}

When the top transformation is used, it will return the top N records for each group. For best results, use this along with orderBy.

GET /products?$apply=groupby((organizationId), orderBy(createdAt desc) then top(3))

// Response
{
"total": 2,
"count": 2,
"value": [x
{
"organizationId": "org1",
"top": [
{
"id": "product1",
...
},
{
"id": "product2",
...
},
{
"id": "product3",
...
}
]
},
{
"organizationId": "org2",
"top": [
{
"id": "product4",
...
},
{
"id": "product5",
...
},
{
"id": "product6",
...
}
]
},
...
]
}

Transformations: Filter

The filter transformation is used to filter the retrieved resource list. The contents of filter are the same as the $filter query parameter, and can be used to filter the resources before applying other transformations.

GET /products/:productId/variants?$apply=filter(price.amount gt 100)

Transformations: OrderBy

The orderby transformation is used to sort the retrieved resource list. The contents of orderby are the same as the $orderby query parameter, and can be used to sort the resources before applying other transformations.

GET /products?$apply=orderby(createdAt desc)

Transformations: Top

The top transformation is used to limit the number of resources returned.

GET /products?$apply=top(5)