OData Query Options for REST APIs
2sxc supports OData system query options to filter, sort, paginate, and select data from both Data and Query REST endpoints. This allows you to append standard OData parameters to your URLs for powerful data querying.
Tip
OData query options work on both:
- Data endpoints:
.../app/auto/data/[ContentType] - Query endpoints:
.../app/auto/query/[QueryName]
Quick Examples
Filter and sort blog posts:
/app/auto/data/BlogPost?$filter=ShowOnStartPage eq true&$orderby=UrlKey
Get the second blog post (pagination):
/app/auto/data/BlogPost?$orderby=UrlKey&$skip=1&$top=1
Query with filter and sort:
/app/auto/query/nameOfQuery?$filter=EntityType eq 'blogpost' and ShowOnStartPage eq true&$orderby=UrlKey
How OData Works with 2sxc Endpoints
Data Endpoint with OData
The Data REST API endpoint lets you query content-types directly:
[root-path]/app/auto/data/BlogPost?$filter=ShowOnStartPage eq true&$orderby=Created desc&$top=10
This returns the 10 most recent blog posts where ShowOnStartPage is true.
Query Endpoint with OData
The Query REST API endpoint lets you query VisualQuery pipelines:
[root-path]/app/auto/query/BlogPostsFiltered?$orderby=Title&$skip=20&$top=10
This executes your predefined query and then applies additional OData filtering/sorting on top of the results.
Special OData-like Query Options
$casing - Control Field Name Casing
2sxc's OData implementation includes a special $casing option to control the casing of field names in the response.
This is useful for JavaScript clients that prefer camelCase.
&$casing=camel
Note: this was added in v21.02.
Supported OData System Query Options
2sxc uses the ToSic.Sys.OData parser which supports a practical subset of OData v4 system query options.
$filter - Filter Data
Filter results based on conditions.
Supported Operators:
- Comparison:
eq(equals),ne(not equals),gt(greater than),ge(greater or equal),lt(less than),le(less or equal) - Logical:
and(combine conditions) - Negation:
not(negate an expression)
Supported Functions:
contains(field, 'text')- check if field contains textstartswith(field, 'text')- check if field starts with text
Examples:
Simple equality:
$filter=Title eq 'Hello World'
Multiple conditions:
$filter=EntityType eq 'blogpost' and ShowOnStartPage eq true
Contains function:
$filter=contains(Description, 'world')
Starts with function:
$filter=startswith(Name, 'Acme')
Negated contains:
$filter=not contains(Description, 'deprecated')
Numeric comparison:
$filter=Rating gt 4 and Rating le 5
Important
Not Currently Supported:
- Logical
oroperator (onlyandis supported) - Arithmetic operators (
add,sub,mul,div,mod) - Complex nested expressions with mixed
and/or - Many OData functions like
endswith,indexof,tolower, etc.
$orderby - Sort Results
Sort results by one or more fields.
Syntax: $orderby=Field1 [asc|desc], Field2 [asc|desc]
Examples:
Sort by single field ascending (default):
$orderby=Title
Sort descending:
$orderby=Created desc
Sort by multiple fields:
$orderby=Category asc, Created desc
$top - Limit Results
Limit the number of results returned.
Syntax: $top=number
Examples:
Get first 10 items:
$top=10
Combine with ordering:
$orderby=Created desc&$top=5
$skip - Skip Results (Pagination)
Skip a specified number of results (useful for pagination).
Syntax: $skip=number
Examples:
Skip first 20 items:
$skip=20
Pagination (page 2 with 10 items per page):
$skip=10&$top=10
$select - Select Specific Fields
Return only specific fields instead of all entity data.
Syntax: $select=Field1,Field2,Field3
Examples:
Select specific fields:
$select=Title,Created,Id
Select with filter:
$select=Title,Description&$filter=ShowOnStartPage eq true
Query Stream Behavior:
- If a query request explicitly selects exactly one stream, unprefixed OData parameters are merged into that selected stream.
- This includes
$select,$filter,$orderby,$top,$skip, and the other supported system query options. - This works both with a stream in the URL such as
.../query/[your-query-name]/[your-stream-name]?$filter=Status eq 'Published'&$orderby=Title - And with the
streamquery parameter such as.../query/[your-query-name]?stream=[your-stream-name]&$top=10&$select=Field1,Field2 - The merge happens per option, not all-or-nothing. So
[your-stream-name]$filter=...overrides a bare$filter, while a bare$orderbycan still apply if no prefixed[your-stream-name]$orderbyis provided. - If you request multiple streams, use prefixed stream-specific parameters such as
[your-stream-name]$filter=Status eq 'Published'or[your-stream-name]$select=Field1,Field2. $selectstill limits the returned fields even when$filter,$orderby, or$topare also present and the request goes through the full query OData execution path.
Examples:
/app/auto/query/[your-query-name]/[your-stream-name]?$select=Field1,Field2&$filter=Status eq 'Published'&$orderby=Title&$top=10
/app/auto/query/[your-query-name]?stream=[your-stream-name]&[your-stream-name]$filter=Status eq 'Published'&$orderby=Title&$select=Field1,Field2
Special Field Aliases:
2sxc provides convenient aliases for common system fields:
IdorEntityId- Entity IDGuidorEntityGuid- Entity GUIDCreated- Creation dateModified- Last modified dateTitle- Title field
Combining Multiple Options
You can combine multiple OData options in a single request:
/app/auto/data/BlogPost?$filter=ShowOnStartPage eq true&$orderby=Created desc&$skip=10&$top=5&$select=Title,Created,UrlKey
This example:
- Filters for posts where
ShowOnStartPageis true - Sorts by
Createddate descending - Skips the first 10 results
- Returns the next 5 results
- Returns only
Title,Created, andUrlKeyfields
Real-World Examples
Example 1: Latest Published Blog Posts
/app/auto/data/BlogPost?$filter=ShowOnStartPage eq true and contains(Title,'2sxc')&$orderby=Created desc&$top=5&$select=Title,Created,UrlKey
This returns the 5 most recent blog posts that:
- Have
ShowOnStartPageset to true - Contain "2sxc" in the title
- Returns only Title, Created date, and UrlKey
Example 2: Paginated Product List
/app/auto/data/Product?$filter=InStock eq true&$orderby=Name&$skip=20&$top=10
This returns products 21-30 (page 3 with 10 per page) that are in stock, sorted by name.
Example 3: Search Results
/app/auto/query/SearchResults?$filter=startswith(Title,'Getting Started')&$orderby=Title&$select=Title,Description,Url
This executes a predefined query and then filters for items starting with "Getting Started".
Example 4: Single Selected Query Stream with Merged OData
/app/auto/query/[your-query-name]/[your-stream-name]?$select=Field1,Field2&$filter=Status eq 'Published'&$orderby=Title&$top=5
This:
- Applies all unprefixed options to the explicitly selected stream
- Filters and sorts that stream
- Limits the results to 5 items
- Still returns only
Field1andField2
URL Encoding
When using OData query options in URLs, special characters must be URL-encoded:
| Character | Encoded |
|---|---|
| Space | %20 |
' (single quote) |
%27 |
eq |
(no encoding needed) |
Example with encoding:
/app/auto/data/BlogPost?$filter=Title eq 'Hello World'
Becomes:
/app/auto/data/BlogPost?$filter=Title%20eq%20%27Hello%20World%27
Tip
Most HTTP libraries and browsers handle URL encoding automatically.
Limitations and Not Supported
The 2sxc OData implementation focuses on practical, commonly-used features. The following are not currently supported:
Not Parsed/Not Executed
$expand- Expanding related entities$compute- Computed properties$search- Free-text search$count- Inline count- Logical
oroperator in$filter - Arithmetic operators in
$filter(add,sub,mul,div,mod) - Lambda operators (
any,all) - OData functions:
endswith,indexof,substring,toupper,tolower,length,trim,concat,year,month,day,hour,minute,second,date,time, etc. - Spatial/geographic functions
- Type casting and
$itreferences - Deep
$selectwith nested options
Technical Notes
- The parser is permissive and syntax-oriented; it doesn't perform semantic validation
- The execution engine supports a pragmatic subset for stable, predictable behavior
- Filter expressions expect: attribute identifier on the left, literal/value on the right
Performance Considerations
- Use $select to return only needed fields (reduces payload size)
- Filter early using
$filterrather than retrieving all data and filtering client-side - Limit results with
$topto avoid large responses
Technical Implementation
The OData system is built on:
- ToSic.Sys.OData - Minimal, permissive parser based on OASIS OData ABNF
- ODataQueryEngine - Execution engine for the EAV/2sxc data stack
- DataSource Pipeline - Integrates with 2sxc's DataSource architecture
The parser generates an AST (Abstract Syntax Tree) which is then executed against the data source pipeline.
History
- OData support introduced in 2sxc 17 (basic
$select) - Enhanced OData parser in 2sxc 20.x
- Added
$filter,$orderby,$top,$skipsupport in 2sxc 21.00 - Added
$casingsupport in 2sxc 21.02