HCMS Schema - Predefined Queries
{'Advanced API design': 'Predefined lists / queries in the schema.'}
Schema can contain predefined queries that can be used via special endpoints to obtain list of entities found by that query. These lists behave just like standard query/listing endpoints.
The same functionality can be also implemented by passing the query as an argument, but in that case each client needs to know the query. By using a predefined one, client does not need to know it and keep it updated when the schema changes. In other words, the list endpoint is an API which implementation that can be changed while retaining compatibility of a client.
There are two distinct types of lists, with a slightly different semantics and significantly different purpose.
List of schema entities
These lists are available at /entity/{name}/list/{queryName} endpoint and they always search for the entities in this given schema. The query is automatically parsed in the context of this schema, just like the /entity/{name}/ (alternatively, it can be said that it's automatically wrapped by @<name>[ ]).
Queries are defined by property "cs:queries", which must be a JSON object. Each key is the query name, each value is either a string or a JSON object with following properties:
- query: The query expression, just like the query query parameters in the REST API; mandatory.
- Note that this expression is validated at the time of schema create/update and any error is immediately reported.
- order: The sorting expression, just like the order query parameter in the REST API; optional.
- Note that the value of this expression is not validated and any errors are ignored (also the time of execution).
- description: Human-readable description of the query; optional.
The simplified version is just a single string with the query expression.
{
"cs:queries": {
"without-group": {
"query": "!group"
},
"adults": {
"description": "All adult users, sorted by age and name",
"query": "age >= 18",
"order": "age,name"
},
"adults-unsorted": "age >= 18"
}
}
List of related entities
Each of these lists requires a valid entity endpoint (which means a valid id), because it's available at the sub-endpoint /entity/{name}/{id}/related/{queryName} ({entityEndpoint}/related/{queryName}). Presumably, the result is somehow related to this entity; there is, however, no enforcement of this semantics and in theory any query can be used.
- The query can (and should) contain variables which are resolved from the main entity:
- ${id} is a standard variable, resolved to the main entity id (from the endpoint url)
- ${this<pointer>} is a special variable form, available only in these queries and nowhere else. It uses JSON Pointer to look up value from the serialized entity.
- Only pointers starting with slash are supported.
- Like all variable identifiers, this one can also contain only plain (ASCII) letters, digits, slash /, tilde ~, dash - and underscore _. This means that some properties are not accessible this way (there is no way to escape special characters). This limitation might be relaxed in some future version; until then, entity schema design should take this limit into consideration.
- Examples: ${this/id}, ${this/name}, ${this/address/work/street}
- The query is parsed as a mixed query, without any context (just like the by the /query endpoint). This means that
- Result can contain entities of any schema (even multiple ones in one single response).
- Query must effectively contain at least one schema cast @<name>, because otherwise there is no property available to match. There is one exception: generic fulltext query.
- If the main entity is not accessible by the current request, no query is executed at all and the endpoint just returns appropriate error (401, 403, 404).
Queries are defined by property "cs:related.queries", with exactly the same syntax as "cs:queries".
{
"cs:related.queries": {
"authored": {
"query": "@document[author=${id}]",
"order": "-modifiedAt"
}
}
}