Skip to content

Graph

Hentera’s Graph is a simple yet powerful way of querying for almost all data in Hantera. Using very simple declarative object structures, we can describe a query that Hantera will perform for us.

Being a graph, we can navigate between entities as we wish to retrieve related data as we need it. Filters and sorting can be applied at every navigation and you choose which fields you’re interested in.

The main HTTP endpoint for making Graph queries is:

GET /resources/graph

Base Sets

A the start of any query, you need to begin by targeting one of the base sets. These are the sets that provide universal access to nodes of a certain type, for example, Orders or Payments. Every type has a set, usually named the same as the type but in plural. To list all available sets and get additional metadata, such as search-indexed fields, use the below query:

GET /resources/graph/meta

Otherwise, refer to the Graph Types section in the navigation.

Query Format

A query is defined in JSON and declaratively expresses the query, not so different from what you may be used to using SQL. Although the syntax is vastly different. The main idea is that you specify the criterias for the nodes you want, and the Graph will return the resulting matching nodes. What you may not be used to, is how easy it is to fetch related data. While SQL is generally limited to resulting in a table, making joins sometimes rather verbose with a lot of duplicated data, Hantera’s Graph can return a more natural nested object structure.

A query is made up of a navigation, with arguments that define filters and sort orders, a list of fields to return, and potentially nested navigations to fetch related data.

Example: Querying Orders

A simple query that fetches the 10 most recent confirmed orders, their deliveries and order lines, may look like this:

POST https://<hantera-hostname>/resources/graph
Authorization: Bearer <YOUR TOKEN>
Content-Type: application/json
[{
"edge": "orders",
"alias": "o",
"filter": "orderState == 'confirmed'",
"getTotalCount": false,
"limit": 10,
"node": {
"fields": ["orderId", "orderNumber", "channelKey", "customerNumber", "orderTotal", "invoiceAddress.name"],
"navigate": [{
"edge": "deliveries",
"alias": "d",
"getTotalCount": false,
"node": {
"fields": ["deliveryId", "shippingTotal", "dynamic->'myDynamicField'"],
"navigate": [{
"edge": "orderLines",
"node": {
"fields": ["orderLineNumber", "productNumber", "quantity", "unitPrice", "orderLineTotal"]
}
}]
}
}]
}
}]

Required Navigations

Each query navigation has a flag require. If set to true, the left-hand-side node will only be returned if the navigation has at least one related node. This can be combined with a filter to indirectly filter the first node based on a related node’s field value.

Authorization

The Graph maps onto Hantera’s resource tree based on node types as such:

graph/<node type>/<node id>

Each node has a primary key, usually a UUID. This can be used to allow access to only specific nodes in the graph.

Query Permissions

In order to be able to query for nodes, a session must have the query permission. For example, the below ACE allows querying of order nodes:

graph/order:query

With query permission you can filter on any field and retrieve the total count. It’s allso a pre-requisite to retrieve field data.

To give access to an order with orderId db974a97-e5ca-4114-95de-2a9ade600257, use:

graph/order/db974a97-e5ca-4114-95de-2a9ade600257:query

Field Permissions

The query permissions authorizes queries, but no field information. In order to authorize fields, use the field permission with optional sub-permission for each field:

graph/order:field:orderNumber

The above ACE authorizes the field orderNumber to be retrieved on order nodes.

Complex Fields

Some fields are objects, examples are dynamic and invoiceAddress. While these are referenced using dot/arrow-notation when querying, the ACE for them are using colon. This allows permissions to be given on all sub-fields:

graph/order:field:dynamic

Or just a single dynamic field:

graph/order:field:dynamic:myField

Attribute Based Access

ABAC is supported for the query permission. This means that querying of nodes can be restricted based on user access attributes. All node fields are available as attributes.

For example:

channelKey@graph/order:query

An even more general ACE can be specified. In this case, the ACE is ignored if the channelKey attribute doesn’t exist on the given node type:

channelKey@graph:query

GraphQL

Hantera also provides a GraphQL interface for the Graph, which can be accessed at the /graphql endpoint. Refer to the introspection API for more details. We generally recommend using the JSON-based interface for querying due to its more consistent integration with actor queries and more universal support. The GraphQL provides a convenient alternative for exploring the graph using a GraphQL client, or for federated scenarios.