Querying

Publishing queries (http and websockets)

You might decide that instead of submitting queries directly to Orbital, or using one of our SDKs to execute a query programmatically, that you’d rather just publish the query as an HTTP(s) endpoint.

Saved queries

Any queries committed to your taxonomy that have an @HttpOperation annotation will automatically be converted into a HTTP query.

For example:

MyQuery.taxi
import taxi.http.HttpOperation
import taxi.http.PathVariable

@HttpOperation(url = '/api/q/movies/{movieId}', method = 'GET')
query getMoviesAndReivews(@PathVariable("movieId") movieId: MovieId) {
  given { movieId }
  find {
    title : MovieTitle
    reviewScore : ReviewScore
  }
}

Any declared query that’s in a Taxi project published to Orbital can be converted into an HTTP Operation.

HttpOperation annotation

Queries need to have an @HttpOperation annotation:

ParamDescription
urlThe url the query is exposed under. It must start /api/q. Any other query URLs are ignored
methodThe HTTP method to respond to, one of GET,POST,PUT, or DELETE

Variables can be defined in your path using {myVar}, which are then made available in your query declaration using a @PathVariable annotation.

Heads up!

For security reasons, queries are only exposed under the /api/q endpoint. Any queries where url in the @HttpOperation annotation starts with something other than /api/q are ignored

Declaring the query

Named queries are defined using a query syntax:

Path Variables

Path variables can be specified by using the taxi.http.PathVariable annotation:

import taxi.http.PathVariable
// Declares a query named getMoviesAndReviews`
query getMoviesAndReviews(
   // Define variables to be passed in
   @PathVariable("movieId") movieId: MovieId
) { ... }

Request Body

For a POST query, the request body is also available, use taxi.http.RequestBody annotation:

import taxi.http.RequestBody

query doASearch(@RequestBody searchRequest: SearchRequest) {
 ...
}

Given clause

If you’ve written Taxi queries before, you’re used to using the given clause to provide data into the query.

For saved queries, that data is often passed as a variable, so the syntax is slightly different:

import taxi.http.PathVariable
// Not a saved query, given clause has a value:
given { movieId: MovieId = 123 }
find { ... }

// A saved query, the movieId comes from the params:
query findMoviesAndReviews(@PathVariable(...) movieId: MovieId) {
  given { movieId } // exposes the parameter into the query as a fact.
  find { ... }
}

Streaming Results with Server-Sent Events (SSE)

To receive query results as a continuous stream of Server-Sent Events, set the Accept header to text/event-stream.

This method can be applied to both standard Request/Response queries and streaming queries.

When using SSE, especially with queries returning multiple records (e.g., database queries), the time-to-first-byte is generally faster. This efficiency is due to records being transmitted as soon as they become available, unlike the standard approach where all records are delivered together at the end of the request.

Example request using curl:

curl -X GET 'http://localhost:9022/api/q/streamingTest' \
  -H 'Accept: text/event-stream;charset-UTF-8'

Saved streams

Streaming queries can be exposed over either HTTP (using Server-Sent Events), or Websocket (or both).

Saved streams are executed in the background by Orbital. By connecting to the output stream, you can observe the results.

Note that when you observe a result feed from a streaming query, results are published from the point the request is received. Previous results are not published on result stream.

Heads up!

You can expose streaming queries on both Server-Sent event endpoints and Websockets - simply add both the annotations.

Publishing on WebSocket

To publish a query over a websocket, annotate the query with the WebsocketOperation annotation, declaring the path:

Heads up!

For security reasons, websocket streams are only exposed under the /api/s path. Any queries where path in the @WebsocketOperation annotation starts with something other than /api/s are ignored
import taxi.http.WebsocketOperation

@WebsocketOperation(path = '/api/s/newReleases')
query getNewReleaseAnnouncements {
  stream { NewReleaseAnnouncement } as {
    title : MovieTitle
    reviewScore : ReviewScore
  }[]
}

Publishing as Server-Sent events

Streaming queries can also be published over HTTP by declaring a @HttpOperation, and then requesting a text/event-stream response:

import taxi.http.HttpOperation

@HttpOperation(url = '/api/q/newReleases', method = 'GET')
query getNewReleaseAnnouncements {
  stream { NewReleaseAnnouncement } as {
    title : MovieTitle
    reviewScore : ReviewScore
  }[]
}

Once this is published, results can be streamed by requesting a text/event-stream:

curl -X GET 'http://localhost:9022/api/q/newReleases' \
  -H 'Accept: text/event-stream;charset-UTF-8'

Live Reload

Any changes made to the queries are automatically deployed.

  • When developing locally, this is as soon as you save a file.
  • In production, when using a Git repository, as soon as changes are merged, they’re deployed on the next poll (typically a couple of minutes)

OpenAPI

Orbital automatically creates an OpenAPI spec for any query endpoints it serves.

The OpenAPI specs are available at /api/q/meta/{nameOfQuery}/oas.

For example, a query defined as query findMoviesAndReviews(...) would have an OpenAPI spec available at /api/q/meta/findMoviesAndReviews/oas

Previous
Streaming data
Next
Query lineage and observability