- What is the universe?
- Structure
- Retrieve a users' universe
- estimated count and isHuge flag
- Listing URL
- Transitions
- References
What is the universe?
The universe holds detailed information about the database model and the api, based on a user's permissions.
This means that it might look different for every user of a system.
The first call to retrieve the universe is relatively slow as it needs to get generated taking all of the user's permissions into account, after that it is cached and the call will be very fast and inexpensive.
The cache gets invalidated if the underlying model changes.
Structure
The universe has this basic structure:
#!json
{
"version" : "ca75c33bc98c97c9bc17334c6b79b0709bd1e753f3067338bc49d9eaa67f38e4",
"plugins" : { },
"apiSettings" : { },
"clientSettings" : { },
"model" : { },
"queryParameters": { },
}
version
Each version is unique for the database model.
plugins
All plugins available to the user are listed and fully defined in this section.
#!json
{
"plugins": {
"password_reset_token": {
"name": "password_reset_token",
"invocationUrl": "/plugins/password_reset_token",
"description": "password_reset_token",
"requestBodyExample": {
"email": "noreply@example.com"
},
"invocationVerb": "POST",
"requestBodyContentType": "application/json; charset=UTF-8",
"jjvInputValidator": {
"additionalProperties": false,
"type": "object",
"required": [
"email"
],
"properties": {
"email": {
"type": "string"
}
}
}
}
}
}
clientSettings
These are settings for the current user, as set in the database.
#!json
{
"clientSettings": {
"thousandSeparator": ",",
"loginName": "root",
"isSystemLanguage": true,
"lastName": "root",
"dateFormat": "MM/DD/YYYY",
"decimalSeparator": ".",
"firstName": "root",
"languageIsoCode": "en",
"languageName": "English",
"isRightToLeft": false,
"emailAddress": "noreply@example.com",
"timeFormat": "mm:ss"
}
model
The main part of the universe. It lists all modules, their entities with attributes and possible Transitions. It also provides the urls for possible Queries.
#!json
{
"model": {
"system": {
"name": "system",
"label": "system"
"isUserDefinedModule": false,
"entities": {
"client": {
"id": 10,
"name": "client",
"label": "client",
"readOnly": false,
"isUserDefinedEntity": false,
"estimatedCount": 1,
"isHuge": false
"isTree": false,
"workflowVerb": null,
"workflowUrl": null,
"queryVerb": "POST",
"queryUrl": "/data/system/client/query",
"instanceRetrievalVerb": "GET",
"instanceRetrievalUrl": "/data/system/client/{{id}}",
"instanceQueryVerb": "POST",
"instanceQueryUrl": "/data/system/client/{{id}}/query",
"instanceCountVerb": "GET",
"instanceCountUrl": "/data/system/client/count",
"instanceLogVerb": "POST",
"instanceLogUrl": "/data/system/client/{{id}}/log",
"auto_ident": {
"columns": [
"me.login_name"
],
"concat": "concat_ws('/',me.login_name)",
"join": null
},
"attributes": {
"last_name": {
"referenceDetails": null,
"isReference": false,
"baseDataType": "text",
"dataType": "text",
"id": 58,
"isSystemAttribute": false,
"label": "last_name",
"description": "last name of client",
"displayOrder": 3,
"required": true,
"name": "last_name"
},
"modifying_action": {
"displayOrder": 253,
"required": true,
"name": "modifying_action",
"dataType": "bigint",
"id": 253,
"isSystemAttribute": true,
"label": "modifying_action",
"description": "reference to the last performed transition",
"referenceDetails": {
"resolveVerb": "GET",
"targetEntity": "action",
"resolveUrl": "/data/system/action/{{modifying_action}}",
"targetModule": "system",
"targetAttribute": "id"
},
"isReference": true,
"baseDataType": "bigint"
},
...
},
"transitions": {
"delete": {
"invocationUrl": "/data/system/client/{{id}}/transitions/delete",
"id": 32,
"requestBodyContentType": "application/json; charset=UTF-8",
"label": "delete",
"description": "A transition that deletes an instance",
"requestBody": {
"successor": "{{successor}}"
},
"preStateID": null,
"postState": null,
"name": "delete",
"invocationVerb": "DELETE",
"attributes": {
"successor": {
"name": "successor",
"required": false
}
},
"preState": null,
"postStateID": null,
"category": "delete"
},
...
},
...
},
...
},
...
}
}
queryParameters
This section defines which parameters are available for the different queries.
#!json
{
"queryParameters": {
"instanceLogParameters": {
"page_size": {
"description": "size of page",
"dataType": "integer",
"name": "page_size"
},
"page": {
"name": "page",
"description": "which page",
"dataType": "integer"
}
},
"entityQuery": {
"id": {
"description": "id of saved queries in extensions.query entity.",
"dataType": "bigint",
"name": "id"
},
"context": {
"name": "context",
"dataType": "json",
"example": {
"attribute": "entity",
"module": "extensions",
"transition": "add",
"entity": "query"
},
"description": "Entity, transition and attribute defining the context the entity should be filtered with."
},
...
}
}
}
apiSettings
Parameters set in the api which are relevant to using the api.
#!json
{
"apiSettings": {
"version": "1.0",
"isHugeLimit": 1000000,
"maxPageSize": "1000"
}
Retrieve a users' universe
GET /universe
#!json
{
"version": "ca75c33bc98c97c9bc17334c6b79b0709bd1e753f3067338bc49d9eaa67f38e4",
"plugins": [
{
"jjvInputValidator": {
"additionalProperties": true,
"type": "object"
},
"invocationVerb": "POST",
"name": "generate_uuid",
"invocationUrl": "/plugins/generate_uuid",
"requestBodyExample": {},
"description": "This function returns a generated UUID"
},
...
Use the "from-db" option to discard the cache.
GET /universe?from-db=1
To only get the current version of the universe:
GET /universe/version
{
"version": "b6c10140387bce47343af695803c0bb7b63304f040ec4a5c7acfc96ff97fe107"
}
Note that this reply, unlike the universe retrieval is not cached. It can be used to check if the cached version is the most current version or if the uncaching has failed for some reason. It is a fairly expensive query for the database though.
To get a specific version of a users' universe:
GET /universe/b6c10140387bce47343af695803c0bb7b63304f040ec4a5c7acfc96ff97fe107
{
"clientSettings": {
"languageIsoCode": "en",
"timeFormat": "mm:ss",
"emailAddress": "noreply@example.com",
"languageName": "English",
"firstName": "root",
"lastName": "root",
"isRightToLeft": false,
"dateFormat": "MM/DD/YYYY",
"isSystemLanguage": true,
"thousandSeparator": ",",
"loginName": "root",
"decimalSeparator": "."
},
"plugins": [
{
"description":
...
Again, this is not cached and asks the database.
estimated count and isHuge flag
Every entity entry in the universe has an "estimatedCount" flag, and derived from it (based on an API config variable), "isHuge".
For any entity that "isHuge" the following restrictions apply:
- joining a 1:n relation is not allowed
- searching can only be done on indexed attributes
- the count for a filter result will be an estimate only
So, this means that for a not "isHuge" entity:
- joining a 1:n relation is allowed
- all attributes are searchable, independant of indexing
- the count for a filter result will be an accurate count
Listing URL
To get instances in store.product, use the information to send a query:
{
"queryUrl": "/data/store/product/query",
"queryVerb": "POST"
}
Look into the Queries documentation for more details.
Transitions
The transitions for an entity in the universe lists all transitions that may be available for the user. Depening on the state and acls of an instance, only a subset may actually be available for an instance. This is the endpoint to query which are actually available:
GET /data/{{module}}/{{entity}}/{{id}}/transitions
e.g. GET /data/system/entity/1/transitions
{
"data": [
{
"id": 6,
"description": "action that modifies an instance",
"modifying_client": 1,
"successor": null,
"action_type": 2,
"modification_time": "2018-06-04 10:25:32.7335",
"label": "edit",
"instance_entity": 6,
"modifying_action": 13,
"notification": null,
"name": "edit",
"entity": 3,
"binding_entity": null
},
{
"modifying_client": 1,
"successor": null,
"id": 7,
"description": "action that explicitly confirms the retrieval of an instance. It does not return any instance data rather than the success of the confimation.",
"action_type": 2,
"modification_time": "2018-06-04 10:25:32.733506",
"modifying_action": 13,
"notification": null,
"label": "read",
"instance_entity": 6,
"binding_entity": null,
"name": "read",
"entity": 3
},
{
"entity": 3,
"name": "delete",
"binding_entity": null,
"label": "delete",
"instance_entity": 6,
"modifying_action": 13,
"notification": null,
"action_type": 3,
"modification_time": "2018-06-04 10:25:32.733512",
"id": 8,
"description": "action that deletes an instance",
"modifying_client": 1,
"successor": null
}
]
}
Note that this is a very expensive query to run, so must not be used without thinking first.
Each transition has a "category". If the category is "create" you can display a button [+] which leads to the form for creating an instance of the given entity.
References
Looking at system.entity we see that modifying_client is a reference:
{
"attributes": {
...
"modifying_client": {
"description": "reference to the client who performed the last change",
"id": 219,
"widgetName": "bigint",
"required": true,
"label": "modifying_client",
"dataType": "bigint",
"name": "modifying_client",
"isReference": true,
"referenceDetails": {
"targetModule": "system",
"resolveUrl": "/data/system/client/{{modifying_client}}",
"targetEntity": "client",
"targetAttribute": "id",
"resolveVerb": "GET"
},
"isSystemAttribute": true,
"displayOrder": 219
},
...
}
Now there are various ways to get the data for this reference.
- use default instance query
The default instance query will automatically join 1:1 relations:
POST /data/system/entity/1/query
{
"data": {
"modification_time": "2018-06-04 10:25:32.728015",
"modifying_client": {
"locked": null,
"email": "noreply@example.com",
"language": 1,
"modifying_action": 29,
"modification_time": "2018-06-04 10:25:32.748609",
"password_validation_period": null,
"first_name": "root",
"password": "15f387d6d56522516a14affa99be6e02",
"number_of_unsuccessfull_login_attempts": null,
"login_name": "root",
"id": 1,
"successor": null,
"modifying_client": 1,
"last_name": "root"
},
...
- use custom instance query
Let's just get first name and last name of the referenced client.
POST /data/system/entity/1/query
{"attrs" : { "join" : "modifying_client", "+columns" : ["modifying_client.first_name","modifying_client.last_name"] } }
{
"data": {
"modification_time": "2018-06-04 10:25:32.728015",
"modifying_client": {
"last_name": "root",
"first_name": "root"
},
"name": "data_type",
"module": 2,
"is_successor_not_required": 0,
"modifying_action": 5,
"label": "data_type",
"is_functional": 0,
"instance_entity": 3,
"is_translatable": 1,
"successor": null,
"id": 1,
"description": "type of data"
},
...
- use resolveUrl to the referenced instance with a seperate request
GET /data/system/client/1
{
"data": {
"language": 1,
"instance_entity": 10,
"modifying_action": 29,
"locked": null,
"email": "noreply@example.com",
"number_of_unsuccessfull_login_attempts": null,
"login_name": "root",
"id": 1,
"successor": null,
"modifying_client": 1,
"last_name": "root",
"modification_time": "2018-06-04 10:25:32.748609",
"first_name": "root",
"password_validation_period": null,
"password": "15f387d6d56522516a14affa99be6e02"
}
}