GraphQL Guide

Disclaimer: Cayley's GraphQL implementation is not strictly a GraphQL, but only a query language with the same syntax and mostly the same rules.

We will use this simple dataset for our examples.

Every query is represented by tree-like structure of nested objects and properties, similar to MQL.

{
  nodes{
    id
  }
}

This particular query is equivalent to all nodes in the graph, where id is the special field name for the value of the node itself.

First root object in traditional GraphQL (named nodes here) represents a method that will be called on the server to get results. In our current implementation this name serves only as a placeholder and will always execute the object search query.

Our example returns the following result:

{
  "data": {
    "nodes": [
      {"id": "bob"},
      {"id": "status"},
      {"id": "cool_person"},
      {"id": "alice"},
      {"id": "greg"},
      {"id": "emily"},
      {"id": "smart_graph"},
      {"id": "predicates"},
      {"id": "dani"},
      {"id": "fred"},
      {"id": "smart_person"},
      {"id": "charlie"},
      {"id": "are"},
      {"id": "follows"}
    ]
  }
}

First level of JSON object corresponds to a request itself, thus either data field or errors will be present.

Any nested objects will correspond to fields defined in query, including top-level name (nodes).

Limit and pagination

Maximal number of results can be limited using first keyword:

{
  nodes(first: 10){
    id
  }
}

Pagination can be done with offset keyword:

{
  nodes(offset: 5, first: 3){
    id
  }
}

This query returns objects 5-7.

Note: Values might be sorted differently, depending on what backend is used.

Properties

Predicates (or properties) are added to the object to specify additional fields to load:

{
  nodes{
    id, status
  }
}

Results:

{
  "data": {
    "nodes": [
      {"id": "bob", "status": "cool_person"},
      {"id": "greg", "status": "cool_person"},
      {"id": "dani", "status": "cool_person"},
      {"id": "greg", "status": "smart_person"},
      {"id": "emily", "status": "smart_person"}
    ]
  }
}

All predicates are interpreted as IRIs and can be written in plain text or with angle brackets: status and <status> are considered equal. Also, well-known namespaces like RDF, RDFS and Schema.org can be written in short form and will be expanded automatically: schema:name and <schema:name> will be expanded to <http://schema.org/name>.

Properties are required to be present by default and can be set to optional with @opt or @optional directive:

{
  nodes{
    id
    status @opt
  }
}

Results:

{
  "data": {
    "nodes": [
      {"id": "bob", "status": "cool_person"},
      {"id": "status"},
      {"id": "cool_person"},
      {"id": "alice"},
      {"id": "greg", "status": ["cool_person", "smart_person"]},
      {"id": "emily", "status": "smart_person"},
      {"id": "smart_graph"},
      {"id": "predicates"},
      {"id": "dani", "status": "cool_person"},
      {"id": "fred"},
      {"id": "smart_person"},
      {"id": "charlie"},
      {"id": "are"},
      {"id": "follows"}
    ]
  }
}

Note: Since Cayley has no knowledge about property types and schema, it might decide to return a property as a single value for one object and as an array for another object. This behavior will be fixed in future versions.

Nested objects

Objects and properties can be nested:

{
  nodes{
    id
    follows {
      id
    }
  }
}

All operations available on root also works for nested object, for example the limit:

{
  nodes(first: 10){
    id
    follows(first: 1){
      id
    }
  }
}

Reversed predicates

Any predicate can be reversed with @rev or @reverse directive (search for "in" links instead of "out"):

{
  nodes{
    id
    followed: <follows> @rev {
      id
    }
  }
}

Filters

Objects can be filtered by specific values of properties:

{
  nodes(id: <bob>, status: "cool_person"){
    id
  }
}

Only exact match is supported for now.

GraphQL names are interpreted as IRIs and string literals are interpreted as strings. Boolean, integer and float value are also supported and will be converted to schema:Boolean, schema:Integer and schema:Float accordingly.

Labels

Any fields and traversals can be filtered by quad label with @label directive:

{
  nodes{
    id
    follows @label(v: <fb>) {
      id, name
      follows @label {
        id, name
      }
    }
  }
}

Label will be inherited by child objects. To reset label filter add @label directive without parameters.

Expanding all properties

To expand all properties of an object, * can be used instead of property name:

{
  nodes{
    id
    follows {*}
  }
}

Un-nest objects

The following query will return objects with {id: x, status: {name: y}} structure:

{
  nodes{
    id
    status {
      name
    }
  }
}

It is possible to un-nest status field object into parent:

{
  nodes{
    id
    status @unnest {
      status: name
    }
  }
}

Resulted objects will have a flat structure: {id: x, status: y}.

Arrays fields cannot be un-nested. You can still un-nest such fields by providing a limit directive (will select the first value from array):

{
  nodes{
    id
    statuses(first: 1) @unnest {
      status: name
    }
  }
}

Last updated