Query API

Release
1.0.2
Status
STABLE
Date
24 Apr 2021
API Endpoint
{baseUrl}/v1/query
© 2003 - 2021 The openEHR Foundation
The openEHR Foundation is an independent, non-profit foundation, facilitating the sharing of health records by consumers and clinicians via open specifications, clinical models and open platform implementations.
Licence image Creative Commons Attribution-NoDerivs 3.0 Unported. https://creativecommons.org/licenses/by-nd/3.0/
Support Issues: Problem Reports
Web: specifications.openEHR.org

Amendment Record

Issue Details Raiser, Implementer Completed
Release-1.0.2
4.1 SPECITS-41: Add double quotes to ETag and If-Match headers S Iancu 21 Mar 2021
4.0 SPECITS-47: Fix inconsistency over query_parameter(s) P Pazos, S Iancu 06 Mar 2021
Release-1.0.1
3.1 SPECITS-37: Fix query definition endpoint and content-type errors P Pazos, J Smolka, S Iancu 01 Oct 2019
3.0 SPECITS-32: Fix typos and minor documentary errors (fixes SPECPR-252, SPECPR-255) E Sundvall, T Beale, S Iancu 1 Sep 2019
2.2 SPECITS-24: Added changelog J Smolka, S Iancu 12 May 2019
SPECITS-25, SPECITS-29: Change layout and structure J Smolka, S Iancu 12 May 2019
SPECITS-30: Fix typos, links, examples and few other minor errors S Iancu 12 May 2019
2.1 Update links to new openEHR specifications website S Iancu 16 Dec 2018
Release-1.0.0

Requirements

Purpose

This specification describes the service endpoints and data-models used when querying an openEHR system. The Archetype Query Language (AQL) is the primary query language.

Query types

Single EHR queries

A common use-case is to execute queries within a specific EHR. This is achieved by supplying a ehr_id query parameter or setting a openEHR-EHR-id request header.

Population queries

Population queries are queries which are executed on several EHRs in the same request. Examples of use-cases can be:

  • Ward lists

  • Explore correlations between patients in a pandemic situation

  • Research, e.g. epidemiology, population health

Stored queries

Stored queries are queries which have their definition stored (registered) on the server. The queries will expose mandatory and optional parameters for the clients.

Using stored queries has lots of advantages:

  • separation of responsibilities (some users/developers write queries, others just call/execute them and consume the responses)

  • no need to pass long query string over the network

Stored queries are identified by name, used as qualified_query_name, and an optional version number in SEMVER style (i.e. major.minor.patch).

Usually a qualified_query_name has a format like <namespace>::<query-name> (e.g. org.openehr::compositions).

If only a partial version is supplied or version is not supplied at all, the system must use the latest version with the supplied prefix - i.e. if only major or major.minor is used, then the latest query version with supplied prefix will be used.

Queries can be stored or, once stored, their definition can be retrieved using the definition endpoint.

Common Headers and Query Parameters

All query execution requests SHOULD support at least the following parameters:

  • ehr_id - used to execute the query within a single EHR context: an EHR identifier taken from EHR.ehr_id.value

  • offset - used for paging: the row number in result to start result-set from (0-based); default 0

  • fetch - used for paging: the number of rows to fetch (i.e. limit); default depends on the implementation, but cannot be combined with AQL-top

  • other parameter(s) to replace placeholder(s) within the query, here generically named query_parameters (see below).

Related request headers:

  • openEHR-EHR-id - used to execute the query within a single EHR context: an EHR identifier taken from EHR.ehr_id.value

Related response headers:

  • ETag - A unique identifier of the resultSet

About the ehr_id parameter

This parameter SHOULD be supplied by clients when executing single EHR queries and MAY be used by the underlying backend to perform routing, optimizations or similar. It MUST NOT be supplied for ‘population queries’ and similar multi-patient queries.

Depending on the needs, clients MAY supply it as a query parameter ehr_id or alternatively as a request header named openEHR-EHR-id.

Query parameters

Depending on each query definition, various query parameters SHOULD be supported, generically named query_parameters in this specification, but in the real request they will have specific names (e.g. uid, systolic_bp, etc.) according to their names in the query definition.

Provided query parameters SHOULD NOT be prefixed with $ sign. Instead, the server will (whenever necessary) add the prefix or format queries as valid AQL queries.

As an example, for the following AQL query

SELECT c/name/value FROM COMPOSITION c WHERE c/uid/value = $uid

named as 'myQuery', the client can supply the uid as a query parameter:

GET {baseUrl}/query/myQuery?uid=90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1

As another example, the request

GET {baseUrl}/query/com.vendor::compositions?temperature_from=36&temperature_unit=Cel

will pass query parameters temperature_from and temperature_unit to the underlying AQL query named com.vendor::compositions.

See AQL-parameters specification for more details.

Request structure

Below is a mostly self-documented AQL query request.

{
    "q": "select o/data[at0002]/events[at0003 and name/value='Any event']/data[at0001]/items[at0004]/value/magnitude as temperature, o/data[at0002]/events[at0003 and name/value='Any event']/data[at0001]/items[at0004]/value/units as unit from EHR[ehr_id/value='554f896d-faca-4513-bddf-664541146308d'] CONTAINS Observation o[openEHR-EHR-OBSERVATION.body_temperature-zn.v1] WHERE o/data[at0002]/events[at0003 and name/value='Any event']/data[at0001]/items[at0004]/value/magnitude > $temperature and o/data[at0002]/events[at0003 and name/value='Any event']/data[at0001]/items[at0.63 and name/value='Symptoms']/value/defining_code/code_string=$chills order by temperature desc fetch 3",
    "query_parameters": {
        "temperature": 38.5,
        "chills": "at0.64"
    }
}

GET vs POST

Requests based on the GET method have URI length restriction, or some characters might not be allowed and have to be encoded. Long queries in the q parameter and having a long list of query_parameters may add up to reach that limit, thus we recommend clients using the POST method instead of GET.

Response structure

Metadata

Field Description
_href URL of the query executed (only for GET endpoint)
_type Defines type of the serialized object
_schema_version The version of the specification defining the serialized object
_created Result creation time (in the extended ISO 8601 format)
_generator Some identifier of the application that generated the result. Useful i.e. for debugging
_executed_aql The actual query (i.e. AQL) that was executed by the server after exploding the parameters. This attribute is not mandatory, but is useful for debugging

Data

Field Description
name Name of a query when registered as a stored query
q The AQL which was given in the request
columns Columns are defined by the client provided with the given AQL. I.e. select c/uid/value as CidValue, c/context/start_time as StartTime from .... will give two columns. One columns for CidValue and another for StartTime.
columns.name Name of the column. I.e. CidValue or StartTime from the example above, when column alias is not present in the AQL a 0-based column index is used prefixed by a hash sign (i.e. #0, #1…)
columns.path Path from the given AQL of the specified column. I.e. columns CidValue will have path /uid/value
rows Ordered list with results.
rows.row Each row list of cells. One cell for each column. Content of a cell is ANY (i.e. a OBJECT in most programming languages)

ResultSet example

Below is a synthesized response with all attributes.

{
                "meta": {
                    "_href": "... the URI for the executed AQL - used only for GET executions ...",
                    "_type": "RESULTSET",
                    "_schema_version": "1.0.0",
                    "_created": "2017-08-19T00:25:47.568+02:00",
                    "_generator": "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)",
                    "_executed_aql": "... the executed aql ..."
                },
                "name": "... the name or identifier of the stored query that was executed ...",
                "q": "SELECT e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
                "columns": [
                    {
                        "name": "#0",
                        "path": "/ehr_id/value"
                    },
                    {
                        "name": "startTime",
                        "path": "/context/start_time/value"
                    },
                    {
                        "name": "cid",
                        "path": "/uid/value"
                    },
                    {
                        "name": "#3",
                        "path": "/name"
                    }
                ],
                "rows": [
                    [
                        "81433066-c417-4813-9b29-79783e7bed23",
                        "2017-02-16T13:50:11.308+01:00",
                        "90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1",
                        {
                            "_type": "DV_TEXT",
                            "value": "Labs"
                        }
                    ]
                ]
            }

Query

Actions upon resources of this group are also formally described in the I_QUERY_SERVICE Abstract Service Model interface.

Execute Query

This currently supports AQL queries only, other query types might be added in the future.

GET {baseUrl}/v1/query/aql?q=SELECT ... WHERE ...&ehr_id=7d44b88c-4199-4bad-97dc-d78268e01398&offset=10&fetch=10&query_parameters=
Responses200400408

200 OK is returned when the server is able to execute the query.

Headers
Content-Type: application/json
ETag: "cdbb5db1-e466-4429-a9e5-bf80a54e120b"
Body
{
  "meta": {
    "_href": "... the URI for the executed AQL - used only for GET executions ...",
    "_type": "RESULTSET",
    "_schema_version": "1.0.0",
    "_created": "2017-08-19T00:25:47.568+02:00",
    "_generator": "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)",
    "_executed_aql": "... the executed aql ..."
  },
  "name": "... the name or identifier of the stored query that was executed ...",
  "q": "SELECT e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
  "columns": [
    {
      "name": "#0",
      "path": "/ehr_id/value"
    },
    {
      "name": "startTime",
      "path": "/context/start_time/value"
    },
    {
      "name": "cid",
      "path": "/uid/value"
    },
    {
      "name": "#3",
      "path": "/name"
    }
  ],
  "rows": [
    [
      "81433066-c417-4813-9b29-79783e7bed23",
      "2017-02-16T13:50:11.308+01:00",
      "90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1",
      {
        "_type": "DV_TEXT",
        "value": "Labs"
      }
    ]
  ]
}

400 Bad Request is returned when the server was unable to execute the query due to invalid input, e.g. a request with missing q parameter or an invalid query syntax.

408 Request Timeout is returned when there is a query execution timeout (i.e. maximum query execution time reached, therefore the server aborted the execution of the query).

Execute ad-hoc (non-stored) AQL query
GET/query/aql{?q,ehr_id,offset,fetch,query_parameters}

Execute ad-hoc query, supplied by q parameter, fetching fetch numbers of rows from offset and passing query_parameters to the underlying query engine.

See also details on usage of query parameters.

URI Parameters
HideShow
q
string (required) Example: SELECT ... WHERE ...

the AQL query to be executed

ehr_id
string (optional) Example: 7d44b88c-4199-4bad-97dc-d78268e01398

an optional parameter to execute the query within an EHR context

offset
number (optional) Example: 10

row number in result-set to start result-set from (0-based), default 0

fetch
number (optional) Example: 10

number of rows to fetch, default depends on the implementation

query_parameters
string (optional) 

query parameters (can appear multiple times)


POST {baseUrl}/v1/query/aql
Requestsexample 1
Headers
Content-Type: application/json
Body
{
  "q": "SELECT c FROM EHR e[ehr_id/value=$ehr_id] CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
  "offset": 0,
  "fetch": 10,
  "query_parameters": {
    "ehr_id": "7d44b88c-4199-4bad-97dc-d78268e01398",
    "systolic_bp": 140
  }
}
Responses200400408

200 OK is returned when the server is able to execute the AQL query.

Headers
Content-Type: application/json
ETag: "cdbb5db1-e466-4429-a9e5-bf80a54e120b"
Body
{
  "meta": {
    "_href": "... the URI for the executed AQL - used only for GET executions ...",
    "_type": "RESULTSET",
    "_schema_version": "1.0.0",
    "_created": "2017-08-19T00:25:47.568+02:00",
    "_generator": "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)",
    "_executed_aql": "... the executed aql ..."
  },
  "name": "... the name or identifier of the stored query that was executed ...",
  "q": "SELECT e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
  "columns": [
    {
      "name": "#0",
      "path": "/ehr_id/value"
    },
    {
      "name": "startTime",
      "path": "/context/start_time/value"
    },
    {
      "name": "cid",
      "path": "/uid/value"
    },
    {
      "name": "#3",
      "path": "/name"
    }
  ],
  "rows": [
    [
      "81433066-c417-4813-9b29-79783e7bed23",
      "2017-02-16T13:50:11.308+01:00",
      "90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1",
      {
        "_type": "DV_TEXT",
        "value": "Labs"
      }
    ]
  ]
}

400 Bad Request is returned when the server was unable to execute the query due to invalid input, e.g. a request with missing q parameter or an invalid query syntax.

408 Request Timeout is returned when there is a query execution timeout (i.e. maximum query execution time reached, therefore the server aborted the execution of the query).

Execute ad-hoc (non-stored) AQL query
POST/query/aql

Execute ad-hoc query, supplied by q attribute, fetching fetch numbers of rows from offset and passing query_parameters to the underlying query engine.

See also details on usage of query parameters.


GET {baseUrl}/v1/query/org.openehr::compositions/1.0?ehr_id=7d44b88c-4199-4bad-97dc-d78268e01398&offset=10&fetch=10&query_parameters=
Responses200400404408

200 OK is returned when the server is able to execute the query.

Headers
Content-Type: application/json
ETag: "cdbb5db1-e466-4429-a9e5-bf80a54e120b"
Body
{
  "meta": {
    "_href": "... the URI for the executed AQL - used only for GET executions ...",
    "_type": "RESULTSET",
    "_schema_version": "1.0.0",
    "_created": "2017-08-19T00:25:47.568+02:00",
    "_generator": "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)",
    "_executed_aql": "... the executed aql ..."
  },
  "name": "... the name or identifier of the stored query that was executed ...",
  "q": "SELECT e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
  "columns": [
    {
      "name": "#0",
      "path": "/ehr_id/value"
    },
    {
      "name": "startTime",
      "path": "/context/start_time/value"
    },
    {
      "name": "cid",
      "path": "/uid/value"
    },
    {
      "name": "#3",
      "path": "/name"
    }
  ],
  "rows": [
    [
      "81433066-c417-4813-9b29-79783e7bed23",
      "2017-02-16T13:50:11.308+01:00",
      "90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1",
      {
        "_type": "DV_TEXT",
        "value": "Labs"
      }
    ]
  ]
}

400 Bad Request is returned when the server was unable to execute the query due to invalid input, e.g. at least one of the parameters has an invalid syntax.

404 Not Found is returned when a query with qualified_query_name and version does not exist.

408 Request Timeout is returned when there is a query execution timeout (i.e. maximum query execution time reached, therefore the server aborted the execution of the query).

Execute stored query
GET/query/{qualified_query_name}/{version}{?ehr_id,offset,fetch,query_parameters}

Execute a stored query, identified by the supplied qualified_query_name (at specified version), fetching fetch numbers of rows from offset and passing query_parameters to the underlying query engine.

See also details on usage of query parameters.

Queries can be stored or, once stored, their definition can be retrieved using the definition endpoint.

URI Parameters
HideShow
qualified_query_name
string (required) Example: org.openehr::compositions

name of the query to be executed

version
string (optional) Example: 1.0

query SEMVER version number

ehr_id
string (optional) Example: 7d44b88c-4199-4bad-97dc-d78268e01398

an optional parameter to execute the query within an EHR context

offset
number (optional) Example: 10

row number in result-set to start result-set from (0-based), default 0

fetch
number (optional) Example: 10

number of rows to fetch, default depends on the implementation

query_parameters
string (optional) 

query parameters (can appear multiple times)


POST {baseUrl}/v1/query/org.openehr::compositions/1.0
Requestsexample 1
Headers
Content-Type: application/json
Body
{
  "offset": 0,
  "fetch": 10,
  "query_parameters": {
    "ehr_id": "7d44b88c-4199-4bad-97dc-d78268e01398",
    "systolic_bp": 140
  }
}
Responses200400404408

200 OK is returned when the server is able to execute the query.

Headers
Content-Type: application/json
ETag: "cdbb5db1-e466-4429-a9e5-bf80a54e120b"
Body
{
  "meta": {
    "_href": "... the URI for the executed AQL - used only for GET executions ...",
    "_type": "RESULTSET",
    "_schema_version": "1.0.0",
    "_created": "2017-08-19T00:25:47.568+02:00",
    "_generator": "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)",
    "_executed_aql": "... the executed aql ..."
  },
  "name": "... the name or identifier of the stored query that was executed ...",
  "q": "SELECT e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name FROM EHR e CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.encounter.v1] CONTAINS OBSERVATION obs[openEHR-EHR-OBSERVATION.blood_pressure.v1] WHERE obs/data[at0001]/events[at0006]/data[at0003]/items[at0004]/value/magnitude >= $systolic_bp",
  "columns": [
    {
      "name": "#0",
      "path": "/ehr_id/value"
    },
    {
      "name": "startTime",
      "path": "/context/start_time/value"
    },
    {
      "name": "cid",
      "path": "/uid/value"
    },
    {
      "name": "#3",
      "path": "/name"
    }
  ],
  "rows": [
    [
      "81433066-c417-4813-9b29-79783e7bed23",
      "2017-02-16T13:50:11.308+01:00",
      "90910cf0-66a0-4382-b1f8-c0f27e81b42d::openEHRSys.example.com::1",
      {
        "_type": "DV_TEXT",
        "value": "Labs"
      }
    ]
  ]
}

400 Bad Request is returned when the server was unable to execute the query due to invalid input, e.g. at least one of the parameters has an invalid syntax.

404 Not Found is returned when a query with qualified_query_name and version does not exist.

408 Request Timeout is returned when there is a query execution timeout (i.e. maximum query execution time reached, therefore the server aborted the execution of the query).

Execute stored query
POST/query/{qualified_query_name}/{version}

Execute a stored query identified by the supplied qualified_query_name (at specified version).

See also details on usage of query parameters.

Queries can be stored or, once stored, their definition can be retrieved using the definition endpoint.

URI Parameters
HideShow
qualified_query_name
string (required) Example: org.openehr::compositions

name of the query to be executed

version
string (optional) Example: 1.0

query SEMVER version number


Generated with aglio on 24 Apr 2021