GraphQL and AllegroGraph | AllegroGraph 9.0.1
Author: Franz Incorporated

Copyright (c) 2005 - 2026 Franz, Incorporated
Last updated 27 May 2026 at 10:34

# AllegroGraph 9.0.1 and GraphQL

- Documentation Index
  - Release Notes
  - Quick Start
  - SSL/TLS Quick Start
  - Introduction
  - Setup and Configuration
    - Download
    - Server Installation
    - Server Configuration and Control
    - WebView
    - Database Upgrading
    - Managing Users
  - Server Management
    - Performance Tuning
    - Deleting Duplicate Triples
    - Purging Deleted Triples
    - Auditing
    - Managing Users
    - Replication
    - Point-in-Time Recovery
    - Transaction Log Archiving
    - Security Overview
    - Security Implementation
  - Tools
    - agtool
    - Data Loading
    - Data Export
    - Backup and Restore
    - Querying
    - RDFS++
    - Materializer
    - Event Scheduler
    - SHACL
  - Details
    - Triple Indices
    - Freetext Indices
    - Encoded IDs
    - Connection Pooling
    - N-dimensional Geospatial Overview
    - 2-D Geospatial
    - Temporal
    - Social Network
    - JavaScript
    - Datatypes
    - Data Conversion (Rapper)
    - Stored Procedures
    - Triple Attributes
    - Lineparse Format
  - Querying
    - SPARQL documentation summary
    - SPARQL Reference
    - SPIN
    - SPARQL Magic Properties
    - Prolog
  - 3rd-party tools
    - Solr text Indices
    - MongoDB integration
    - TopBraid Composer Plugin
    - Cloudera
  - Client APIs
    - Gruff
    - GraphTalker
    - REST/HTTP interface
    - HTTP reference
    - Javadocs (Sesame and Jena)
    - Python API
    - Lisp Reference
    - JavaScript
  - Tutorials
    - N-dimensional Geospatial
    - SPARQL Tutorial
    - Java Sesame
    - Java Jena
    - Python Sesame
    - Lisp
    - Prolog
    - More...
  - Other
    - Conferences and Seminars
    - Source Code on Github
    - Amazon EC2
    - Copyrights
  - Franz, Inc.

- Introduction
- Usage
- Extensions to GraphQL syntax
- GraphQL in AllegroGraph: General description
- GraphQL and RDF triple stores
  - Details
  - Star Wars Example
  - Directives are used to alter how predicates are processed.
- Extensions to GraphQL syntax

Documentation Index

## Introduction

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools. (Description from the GraphQL webpage.)

## Usage

AllegroGraph can run GraphQL queries at `repositories/REPOSITORY/graphql` HTTP endpoint as well as from Lisp using the agq.graphql:run-graphql function.

The HTTP `POST` arguments:

- `default-prefix` - namespace or URI to prepend to GraphQL fields in the query.

- `infer` - Specifies the kind of inference to use for this query. Valid values are `false`, `rdfs++`/`true`, and `hasvalue`.

The next three arguments have as values comma-separated with each item having two space separated parts.

- `namespaces` - comma-separated list of prefix/values separated by spaces. For example

      "foo <http://foo.com/>,bar <http://bar.com/>"

These namespaces shadow `user/repo/default` namespaces (see Namespaces and query options, IRI aliases, and typevars). Space and other special characters must be uuencoded.

- `variables` - comma-separated list of name/values separated by spaces. For example

      "$size 10,$width 20"

- `aliases` - comma-separated list of alias/IRI separated by spaces (see Namespaces and query options, IRI aliases, and typevars).

Here is an example HTTP POST:

    POST /repositories/REPONAME/graphql?default-prefix=http://example.com/&namespaces=rdfs%20http://www.w3.org/2000/01/rdf-schema#

Example curl request to repository 'test' at port 10050 from user `test` with password `xtzzy`:

    curl 'test:xyzzy@localhost:10050/repositories/test/graphql?default-prefix=http://example.com/&namespaces=purl%20http://purl.org/vocab/relationship/' --data-binary @query.gql

    Request body: GraphQL query

Lisp equivalent:

    (with-namespace-abbreviations
        '(("rdfs" . "http://www.w3.org/2000/01/rdf-schema#"))
      (agq.graphql::run-graphql
       my-graphql-query
       :default-prefix "http://example.com/"
       :results-format :list))

Possible values for `:results-format are

- `:json`

- `:list` - the list form of the JSON

- `:listupi` - the list form of the JSON but instead of converting the upis to their `upi->value` so they are readable, we leave the upi's alone which makes them easier to use if you're doing subsequent work with them

When run in AGWebView, GraphQL query results are displayed as pretty-printed JSON. In AGWebView, a user can access it by choosing `GraphQL` as the language in the Query Editor.

Predefined namespaces can be used in the query (see Namespaces and query options)

## Extensions to GraphQL syntax

Additionally, the GraphQL syntax is extended with magic comments (see below for more information):

- default prefix

      full iri:
       #@default <http://example.com/>
      if 'ex' is defined:
       #@default ex

- namespaces (same syntax as in SPARQL after the comment character '#')

      #@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

- aliases

      #@alias type <http://www.w3.org/2000/01/rdf-schema#type>

- string designation: single quotes can be used to designate strings, so 'foo' is the same as "foo". '''string''' is supported like """string""" as well (so within triple quotes or double quotes, everything is in the string and " or ' is just another character.

## GraphQL in AllegroGraph: General description

Summary of the AllegroGraph GraphQL implementation:

- Top Level Operators:

  - queries and fragment operators are supported.

  - type and mutation operators are not supported.

- Directives:

  - Standard directives: `@include(if: boolean)` and `@skip(if: boolean)`

  - Common directives: `@filter(if: "SPARQL expression")`

  - AllegroGraph-specific directives: `@nullable(if: boolean)` which makes it ok for a field in a query to not have a value. `boolean` can be `true` or `false`.

- External specifications (details below):

      #@default <http://some.uri/>
      #@prefix ns: <http://whatever.com/>
      #@alias  myuri  <http://some.long.uri/>

- When used as a boolean value the value `nil` or "false" represent a false value and everything else represents a true value.

## GraphQL and RDF triple stores

In RDF the two main objects are resources and literals. Resources are usually URI's and are in some places written as with the angle brackets not being part of the resource name but simply a means of specifying that the character string inside the brackets denotes a resource.

Literals can be any string and are written surrounded by double quotes.

In GraphQL we have names which consist of letters and digits which cannot be considered a number. There are numbers which are integers or floats. And finally there are strings which is any text surrounded by double quotes.

In the AllegroGraph GraphQL query engine names are considered to be RDF resources. Strings and numbers are considered to be RDF literals.

GraphQL's syntax for names cannot express all RDF resource names so we've extended the GraphQL syntax to include the angle brackets.

You can't write in GraphQL the resource name `http://example.com/Hero` since the colon is not a permitted character in a GraphQL name. So we've extended the syntax of GraphQL and you can write `<http://example.com/Hero>` to name this RDF resource in GraphQL.

Also you may have defined "ex" as a namespace abbreviation for "http://example.com/". You can't write `ex:Hero` in GraphQL since the colon cannot appear in a name. You can write `<ex:Hero>` and the AllegroGraph GraphQL parser will expand the namespace abbreviation to yield `<http://example.com/Hero>`.

Consider

    #@default http://example.com/
    {
        Hero (name: Luke)
         {
            height
            <http://other.com/weight>
         }
    }

Here we see five GraphQL names:

- `Hero`
- `name`
- `Luke`
- `height`
- `http://other.com/weight`

All five of these will turn into resources and the default prefix will be prepended to the first four.

    http://example.com/Hero
    http://example.com/name
    http://example.com/Luke
    http://example.com/height
    http://other.com/weight

If we had written it as

    #@default http://example.com/
    {
        Hero (name: "Luke Skywalker")
         {
            height
            <http://other.com/weight>
         }
    }

Then we have four GraphQL names and one GraphQL string so when this is applied to an RDF store we have four resources:

    http://example.com/Hero
    http://example.com/name
    http://example.com/height
    http://other.com/weight

and one literal

    "Luke Skywalker"

Note that in the directives that follow `#@` you can write a resource with or without the angle brackets.

    #@default http://example.com/

is the same as

    #@default <http://example.com/>

### Details

A query can be explicit

    query myquery($var1: type = value)
    {
        alpha
           { beta
             gamma
           }
    }

or implied

    {
        alpha
           { beta
             gamma
           }
    }

The explicit syntax allows you to specify variables which can be used inside the query.

There is no standard mapping of a GraphQL query to an RDF store like AllegroGraph so we have chosen a mapping that makes the most sense and is similar to the mapping used by other RDF stores.

In this query

    {
        alpha
           { beta
               { delta }
             gamma
           }
    }

`alpha` is the name of a class, and `beta`, `gamma`, and `delta` are predicates.

That is we find all objects `?0` such that:

    ?0 rdf:type alpha

and for each we retrieve the objects of the triples

    ?0 beta ?1

and

    ?0 gamma ?2

and further we look for the `delta` predicate value for those objects pointed to by the `beta` predicate

    ?1 delta ?3

An RDF store consists of triples or quads of resources and literals and blank nodes.

Resources are usually named something like `http://example.com/alpha` and this is written `<http://example.com/alpha>` to denote that this is a resource with that name and not simply that literal string.

In order to make GraphQL easy to write and read we allow one to specify part of the resource name outside the query itself

    #@default <http://example.com/>
    {
        alpha
           { beta
               { delta }
             gamma
           }
    }

says that the default prefix for resources is `http://example.com/` Thus the above is the same as:

    {
        <http://example.com/alpha>
           { <http://example.com/beta>
               { <http://example.com/delta> }
             <http://example.com/gamma>
           }
    }

But the former form is much to read.

You can also declare namespaces as done in SPARQL if a single prefix does not sufice for all resources mentioned, for example:

    #@prefix ex: <http://example.com/>
    {
        <ex:alpha>
           { <ex:beta>
               { <ex:delta> }
             <ex:gamma>
           }
    }

To summarize, a resource can be written in a GraphQL query as

1. a name like `alpha` in which case the default prefix is prepended
2. fully specified like `<http://example.com/alpha>`
3. use a defined namespace to specify the prefix `<ex:alpha>`

AllegroGraph has a set of the common namespaces predefined. See the Namespaces and query options document.

### Star Wars Example

In the following, we'll make use of our version of the Star Wars database commonly used in GraphQL documentation:

    @prefix ex: <http://example.com/> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

    ex:star-wars rdf:type ex:Movie .
    ex:star-wars ex:episode ex:newhope .
    ex:star-wars ex:episode ex:empire .
    ex:star-wars ex:episode ex:jedi .

    ex:newhope rdf:type ex:Episode .
    ex:empire  rdf:type ex:Episode .
    ex:jedi    rdf:type ex:Episode .

    ex:star-wars ex:hero ex:r2-d2 .
    ex:star-wars ex:hero ex:Luke .
    ex:star-wars ex:hero ex:Lando .

    ex:r2-d2 rdf:type ex:Hero .
    ex:Luke  rdf:type ex:Hero .
    ex:Lando rdf:type ex:Hero .

    ex:newhope ex:name "Star Wars" .
    ex:newhope ex:date "May 25, 1977"^^<rdfs:date> .
    ex:newhope ex:number 4 .

    ex:empire ex:name "The Empire Strikes Back" .
    ex:empire ex:date "May 17, 1980"^^<rdfs:date> .
    ex:empire ex:number 5 .

    ex:jedi ex:name "Return of the Jedi" .
    ex:jedi ex:date "May 25, 1983"^^<rdfs:date> .
    ex:jedi ex:number 6 .

    ex:r2-d2 ex:name "R2-D2" .
    ex:r2-d2 rdf:type ex:Robot .
    ex:r2-d2 ex:appearsIn ex:newhope .
    ex:r2-d2 ex:appearsIn ex:empire .
    ex:r2-d2 ex:appearsIn ex:jedi .
    ex:r2-d2 <http://purl.org/vocab/relationship/friendOf> ex:Luke .
    ex:r2-d2 ex:owner ex:Luke .
    ex:r2-d2 ex:primaryFunction "Astromech" .

    ex:Luke ex:name "Luke Skywalker" .
    ex:Luke rdf:type ex:Human .
    ex:Luke ex:appearsIn ex:newhope .
    ex:Luke ex:appearsIn ex:empire .
    ex:Luke ex:appearsIn ex:jedi .
    ex:Luke <http://purl.org/vocab/relationship/friendOf> ex:Lando .
    ex:Luke <http://purl.org/vocab/relationship/friendOf> ex:r2-d2 .
    ex:Luke ex:height "1.60"^^xsd:double .

    ex:Lando ex:name "Lando Calrissian" .
    ex:Lando rdf:type ex:Human .
    ex:Lando ex:appearsIn ex:empire .
    ex:Lando ex:appearsIn ex:jedi .
    ex:Lando <http://purl.org/vocab/relationship/friendOf> ex:Luke .
    ex:Lando <http://purl.org/vocab/relationship/friendOf> ex:r2-d2 .
    ex:Lando ex:height "1.65"^^xsd:double .

Here is very simple query

    {
       <http://example.com/Episode> { <http://example.com/name> }
    }

and the result is JSON which we show here this way to make it more readable

    {
       "<http://example.com/Episode>":
            [
              {
                 "<http://example.com/name>":  "Return of the Jedi",
               },
              {
                 "<http://example.com/name>":  "The Empire Strikes Back",
               },
              {
                 "<http://example.com/name>":  "Star Wars",
               },
              ],
      }

There are multiple Episodes so we have an array of results. Each result shows the name of the Episode.

If we wrote the query this way:

    #@default <http://example.com/>
    {
       Episode { name }
    }

the we get an easier to read result:

    {
       "Episode":  [
                     {
                       "name":  "Return of the Jedi",
                     },
                     {
                       "name":  "The Empire Strikes Back",
                     },
                     {
                       "name":  "Star Wars",
                     },
                   ],
    }

### Directives are used to alter how predicates are processed.

Each GraphQL implementation supports the `@include` and `@skip` directives. We also support the `@nullable` directive which is important since we don't process GraphQL type definitions so normally a type definition specifies which fields are nullable

A field marked as `@nullable` need be present and if it's not present the query will continue and that single field will not be present in the result.

For example

    #@default <http://example.com/>
    {
        Hero
           { name
             height
           }
    }

returns:

    [
       {
         "Hero": [
           {
             "name": "Lando Calrissian",
             "height": "\"1.65E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           },
           {
             "name": "Luke Skywalker",
             "height": "\"1.6E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           }
         ]
       }
    ]

You'll note that `rd-d2` isn't returned since it doesn't have a `height` property. That doesn't seem reasonable since we want a list of heroes and whether or not they have a given `height` should not be important.

So we declare the `height` property to be `nullable`. Directives must take an argument to determine if they are active which is the reason for the `(if: true)`.

Given this:

     #@default <http://example.com/>
     {
         Hero
            { name
              height @nullable(if: true)
            }
     }

we get back a complete list of the heroes but r2-d2 doesn't have a height value returned.

    [
       {
         "Hero": [
           {
             "name": "Lando Calrissian",
             "height": "\"1.65E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           },
           {
             "name": "Luke Skywalker",
             "height": "\"1.6E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           },
           {
             "name": "R2-D2"
           }
         ]
       }
    ]

If you want be explicit about the types for which you want to retrieve a slot you can do the same as the above using the fragment syntax. Here the height property will only be checked if the Hero is also of type Human

    #@default <http://example.com/>
    { Hero
        {name
         ... on Human
            { height }
        }
    }

with the result

    [
       {
         "Hero": [
           {
             "name": "Lando Calrissian",
             "height": "\"1.65E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           },
           {
             "name": "Luke Skywalker",
             "height": "\"1.6E0\"^^<http://www.w3.org/2001/XMLSchema#double>"
           },
           {
             "name": "R2-D2"
           }
         ]
       }
    ]

That was an anonymous fragment. You can also define a fragment and use it by name.

This returns exactly what the previous query returns.

    #@default <http://example.com/>
    { Hero
        {name
         ... humancheck
        }
    }
    fragment humancheck on Human
    {
       height
    }

It's possible to do more than one query in a single invocation of GraphQL as in the following examples.

This:

    #@default <http://example.com/>
    { Hero
        { name }
    }
    {
       Human
        { name }
    }

or this:

    #@default <http://example.com/>
    { Hero
        { name }
       Human
        { name }
    }

will return an array of the results:

    [
       {
         "Human":  [
                     {
                       "name":  "Lando Calrissian",
                     },
                     {
                       "name":  "Luke Skywalker",
                     },
                   ],
       },
       {
         "Hero":  [
                    {
                      "name":  "Lando Calrissian",
                    },
                    {
                      "name":  "Luke Skywalker",
                    },
                    {
                      "name":  "R2-D2",
                    },
                  ],
       },
    ]

The `@filter` directive is given after a name but it actually applies to the whole enclosing object

For example:

    #@default <http://example.com/>
    {
        Hero
         {
            name
            height
            appearsIn @filter(if: "$height > 1.62")
          }
    }

the filter applies to all of

     {
         name
         height
         appearsIn
     }

it could have been placed after any of the name, e.g. this is equivalent:

    #@default <http://example.com/>
    {
        Hero
         {
            name    @filter(if: "$height > 1.62")
            height
            appearsIn
          }
    }

The filter expression is any valid SPARQL expression that might be found in a SPARQL filter clause.

In the filter expression `$xxxx` (`$height` in the example) refers to the value of field named `xxxx`. While `$xxxx` looks like a GraphQL variable, it is not. You can use `$xxxx` to refer to any field name given in the GraphQL expression.

AllegroGraph can run GraphQL queries at `repositories/REPOSITORY/graphql` HTTP endpoint as well as from Lisp using the agq.graphql:run-graphql function.

The HTTP `request` arguments:

- `prefix` - namespace or URI to prepend to GraphQL fields in the query.

- `namespaces` - space-separated list of namespace abbreviations, shadows user/repo/default namespaces. Space and other special characters must be uuencoded.

- `infer` - Specifies the kind of inference to use for this query. Valid values are `false`, `rdfs++`/`true`, and `hasvalue`.

- `var` - space-separated list of values of GraphQL variables.

Here is an example HTTP request:

    POST /reporitories/REPONAME/graphql?default-prefix=http://example.com/&namespaces=rdfs http://www.w3.org/2000/01/rdf-schema#

Example curl request to repository 'test' at port 10050

    curl 'test:xyzzy@localhost:10050/repositories/test/graphql?default-prefix=http://example.com/&namespaces=purl%20http://purl.org/vocab/relationship/' --data-binary @query.gql

    Request body: GraphQL query

Lisp equivalent:

    (with-namespace-abbreviations
        '(("rdfs" . "http://www.w3.org/2000/01/rdf-schema#"))
      (agq.graphql::run-graphql
       my-graphql-query
       :default-prefix "http://example.com/"
       :results-format :alist))

When run in AGWebView, GraphQL query results are displayed as pretty-printed JSON. In AGWebView, a user can access it by choosing "GraphQL" as the language in the Query Editor.

Predefined namespaces can be used in the query.

## Extensions to GraphQL syntax

Additionally, the GraphQL syntax is extended with magic comments:

- default prefix:

      full iri:
       #@default <http://example.com/>
      if 'ex' is defined:
       #@default ex

- namespaces (same syntax as in SPARQL after the comment character '#'):

      #@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

The colon after the namespace abbreviation is optional as are the angle brackets around the resource. So an equivalent declaration is:

    #@prefix rdfs http://www.w3.org/2000/01/rdf-schema#

aliases: The alias magic comment is a bit more complex.

Unlike the other magic comments the angle brackets are important in an alias since it's basically a string substitution

    #@alias type http://www.w3.org/2000/01/rdf-schema#type

is not correct since that's not a good name while

    #@alias type <http://www.w3.org/2000/01/rdf-schema#type>

is correct since you want it to be interpreted a resource.

Some examples using alias:

    #@default <http://example.com/>
    #@alias ain appearsIn
    {
         Hero
          {
             name
             ain
           }
    }

yields:

    [
       {
         "Hero": [
           {
             "name": "Lando Calrissian",
             "appearsIn": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>"
             ]
           },
           {
             "name": "Luke Skywalker",
             "appearsIn": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>",
               "<http://example.com/newhope>"
             ]
           },
           {
             "name": "R2-D2",
             "appearsIn": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>",
               "<http://example.com/newhope>"
             ]
           }
         ]
       }
    ]

and if we instead alias to the full resource name:

    #@default <http://example.com/>
    #@alias ain <http://example.com/appearsIn>
    {
         Hero
          {
             name
             ain
           }
    }

yields:

    [
       {
         "Hero": [
           {
             "name": "Lando Calrissian",
             "<http://example.com/appearsIn>": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>"
             ]
           },
           {
             "name": "Luke Skywalker",
             "<http://example.com/appearsIn>": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>",
               "<http://example.com/newhope>"
             ]
           },
           {
             "name": "R2-D2",
             "<http://example.com/appearsIn>": [
               "<http://example.com/jedi>",
               "<http://example.com/empire>",
               "<http://example.com/newhope>"
             ]
           }
         ]
       }
    ]