Skip to Content
ContributeBackendOData Query Guide

OData Query Guide

List endpoints accept OData-style query parameters — $filter, $select — alongside sort_by, sort_order, skip, and limit. Filtering is handled by the odata-query library against the SQLAlchemy models (app/utils/odata.py).

request.sh
curl -H "Authorization: Bearer YOUR_API_KEY" "https://api.rhesis.ai/tests?$filter=priority eq 1"

Query parameters

ParameterPurposeExample
$filterFilter rows with OData expressions$filter=status/name eq 'Active'
$selectReturn only selected fields (id always included)$select=name,score_type,threshold
sort_bySort fieldsort_by=created_at
sort_orderSort direction (asc or desc)sort_order=desc
skipPagination offsetskip=20
limitMax rows returnedlimit=50

Comparison operators

eq, ne, gt, lt, ge, le:

comparison.sh
GET /tests?$filter=priority eq 1
GET /tests?$filter=priority ne null
GET /tests?$filter=priority gt 0
GET /tests?$filter=priority le 5

String functions

Function-style syntax: function(field, value).

string-functions.sh
GET /behaviors?$filter=contains(name,'Test')
GET /behaviors?$filter=startswith(name,'Test')
GET /behaviors?$filter=endswith(name,'Behavior')

# Case-insensitive search with tolower / toupper
GET /behaviors?$filter=contains(tolower(name),'test')

Traverse relationships with /: relationship/field. This resolves related data in a single request instead of chaining calls.

navigation.sh
GET /tests?$filter=behavior/name eq 'Test Behavior'
GET /tests?$filter=status/name eq 'New'
GET /tests?$filter=topic/name eq 'Security'
GET /tests?$filter=contains(prompt/content,'test')
GET /tests?$filter=contains(tolower(behavior/name),'rel')

Logical operators

Combine conditions with and, or, not, and group with parentheses:

logical.sh
GET /tests?$filter=status/name eq 'New' and priority ne null
GET /tests?$filter=priority eq 1 or priority eq 2
GET /tests?$filter=not (priority eq 1)
GET /tests?$filter=(status/name eq 'New' and priority ne null) or contains(prompt/content,'test')

Sorting and pagination

sort-paginate.sh
GET /tests?sort_by=created_at&sort_order=desc
GET /tests?$filter=status/name eq 'New'&skip=0&limit=50

Field selection with $select

$select takes a comma-separated list of top-level fields and filters the serialized response after the query runs. id is always included so entities stay addressable. It reduces payload size but does not change which rows match $filter.

select.sh
GET /metrics?$select=name,metric_scope
GET /test_results?$filter=test_run_id eq 'run-uuid'&$select=status,prompt,metric_scores

$select works on all standard list endpoints generated through the backend routers.

MCP server-managed pagination

When list operations are called through MCP tools rather than direct REST, some tools define a server-managed page_size in mcp_tools.yaml. In those cases limit is hidden from the model, the server applies a fixed page size with peek-ahead (limit = page_size + 1), and responses are wrapped with _pagination metadata:

mcp-pagination-response.json
{
  "results": [
    {
      "id": "a1",
      "name": "Project A"
    },
    {
      "id": "a2",
      "name": "Project B"
    }
  ],
  "_pagination": {
    "returned": 2,
    "has_more": true,
    "next_skip": 2,
    "hint": "Showing 2 results — there are more. Use $filter to narrow or call again with skip=2 for the next page."
  }
}

For direct REST calls, limit and skip remain client-controlled.

URL encoding

Encode filter values in query strings: space becomes %20, / becomes %2F, ' becomes %27.

url-encoding.sh
GET /tests?%24filter=contains(behavior%2Fname,%27Test%27)

Error responses

Invalid fields or unparseable expressions return 400 with a detail message:

errors.json
{
  "detail": "Error processing filter: Failed to parse at: Token(...)"
}

Use function-style syntax for string operations — contains(behavior/name,'test'), not behavior/name contains 'test'.

Endpoints supporting OData filtering

/tests, /behaviors, /topics, /categories, /test_sets, /test_runs, /test_results, /prompts, /metrics, /projects, and related list routes. Each supports the navigation properties defined by its model relationships.