GraphQL

GraphDB also allows you to explore your data using GraphQL — a simple language for querying various data stores. It is based on a strong type system (schema language) that allows objects and query validation, query autocompletion, and query type checking in modern languages such as TypeScript. It is not a replacement for SPARQL as it does not allow arbitrary queries to be issued. Instead, GraphQL is intended to provide a simple facade over complex backend storage systems.

GraphQL queries have a regular hierarchical structure. Each level is serviced (resolved) in sequence, and lower levels cannot influence the results at a higher level. If you want to order or filter by lower-level data, you often need to access the same fields in the higher-level filter clause, and in the lower-level selection clause.

GraphQL security

Since using GraphQL assumes a more limited access to the data, the GraphDB security mechanism allows administrators to provide users with access only to the GraphQL environment, without enabling access to the RDF layer. In other words, administrators can create GraphQL-only users who won’t be able to use SPARQL, mirroring most real-life use cases of GraphQL.

In addition to the GraphQL-only security check controlled through the User Management screen, a more robust Role-Based Access Control (RBAC) mechanism is also available. Whenever a GraphQL query or mutation is invoked, the RBAC mechanism controls which information is returned and which data can be modified in case of a mutation. The mechanism uses Custom user roles.

See also

Migrating GraphQL configurations from Semantic Objects to GraphDB details the important details and steps when migrating from Semantic Objects to GraphDB 11.

GraphQL endpoints

Usage of GraphQL is done through GraphQL endpoints which provide API access to a repository’s data. The endpoint works through a generated GraphQL schema which specifies how the repository’s classes and properties are treated as GraphQL types and fields. When you create a GraphQL endpoint, you can have GraphDB generate the endpoint from the existing OWL ontologies and SHACL shapes, or use your own GraphQL Schema Shapes Model.

Further down below you can find an example of generating a GraphQL endpoint from a SHACL shape.

See also

The GraphQL schemas and endpoint management documentation provides a thorough overview of the creation, management and usage of GraphQL endpoints.

Licensing GraphQL

Basic GraphQL support is available in all versions of GraphDB, but some advanced options require an additional GraphQL license:

Note

These restrictions apply on an operational level. Schema parsing, validation and loading will work fine even without a valid license. An operation (query or mutation) is stopped only upon execution and only if any of the advanced features are necessary for its execution.

See also

For more information on licensing options, check the Licensing documentation.

GraphQL Playground

The GraphDB Workbench comes with GraphQL Playground — an environment that allows query autocompletion. The GraphQL Playground is built on GraphiQL, a graphical in-browser GraphQL IDE. You can access this interface through GraphQL ‣ GraphQL Playground in the Workbench menu.

To perform a GraphQL query, you must first select an available GraphQL endpoint from the available list of endpoints, found at the top right of the GraphQL Playground interface.

Once you have selected an endpoint from the drop-down menu, you will be able to write and perform GraphQL queries. You can also perform some additional operations:

  • icon-graphql-execute Executes the query and displays the results in the tab to the right.

  • icon-graphql-prettify Automatically formats the GraphQL query, making it easier to read and and work with.

  • icon-graphql-merge-fragments Merges fragments into query. This only works for in-line fragments.

  • icon-graphql-copy Copies the query.

There are several other plugins available in the GraphQL Playground:

  • icon-graphql-docs Opens the Documentation explorer of your schema. This plugin allows you to browse and explore the schema and its types and fields. This is the default plugin found in GraphiQL, and has mostly been superseded by the GraphiQL Explorer, also available in the playground.

  • icon-graphql-history Opens the History tab, which shows previously executed queries. You can mark previous queries as Favorite for quick access.

  • icon-graphql-graphiql-explorer Opens the GraphiQL Explorer, an advanced view of the types and fields available in your schema which also allows you to directly construct queries through its interface.

Using your GraphQL endpoints with the GraphiQL Explorer

Querying GraphQL endpoints in Workbench

The GraphiQL Explorer can present an intuitive display of more advanced data relationships. For example, in addition to showing the Employee and Address classes from a schema as top level types in the illustration below, it also shows that the Employee type has an address field whose value is an instance of the Address type with its city and street fields.

_images/employeeAddressGraphiQLExplorer.png

GraphiQL can also show you the operators that you can use for filtering data from this GraphQL endpoint such as EQ for equals and GT for greater-than. The following shows how the GraphiQL Explorer was used to create a query for all employees with a startDate before June 1, 2024, and on the right we can see the result of the query:

_images/graphqlLTQuery.png

Available operators will come from the following list, depending on the type of the field whose value is used as the filter:

operator

description

example

ALL

For a potentially multivalued field, make sure that all meet a certain condition. For example, if an employee may have more than one address, only select them if “Main” is part of the street value for all of the addresses. This will also select employees who have no address street value.

employee(where: {ALL: {address: {street: {RE: "Main"}}}})

ALL_EXISTS

Like ALL, but the field or fields with the value being checked (in the case of the example, the address street value) must exist for that employee.

employee(where: {ALL_EXISTS: {address: {street: {RE: "Main"}}}})

AND

an array in which all conditions must be true

employee(where: {AND: [ {address: {city: {EQ: "Springfield"}}} {address: {street: {EQ: "24 Hauptstrasse"}}} ]})

EQ

equal to

employee(where: {startDate: {EQ: "2024-06-01"}})

GT

greater than

employee(where: {startDate: {GT: "2024-06-01"}})

GTE

greater than or equal to

employee(where: {startDate: {GTE: "2024-06-01"}})

ID

matches the specified resource ID; for a GraphQL interface to RDF data, the resource’s IRI

employee(ID: "http://example.com/ns/data#emp2")

IN

in the following array as a member

employee(where: {familyName: {IN: ["Evans","Green"]}})

IRE

matches the regular expression (case-insensitive)

employee(where: {familyName: {IRE: "^ev"}})

LT

less than

employee(where: {startDate: {LT: "2024-06-01"}})

LTE

less than or equal to

employee(where: {startDate: {LTE: "2024-06-01"}})

NEQ

not equal to

employee(where: {startDate: {NEQ: "2024-06-01"}})

NIN

not in the following array as a member

employee(where: {familyName: {NIN: ["Evans","Green"]}})

NIRE

doesn’t match the regular expression (case-insensitive)

employee(where: { familyName: {NIRE: "^ev"}})

NRE

doesn’t match the regular expression (case-sensitive)

employee(where: { familyName: {NRE: "^Ev"}})

OR

an array in which at least one of the conditions must be true

employee(where: {OR: [ {address: {city: {EQ: "Springfield"}}} {address: {street: {EQ: "24 Hauptstrasse"}}} ]})

RE

matches the regular expression (case-sensitive)

employee(where: { familyName: {RE: "^Ev"}})

Adding, updating, and deleting data with GraphQL mutations

In addition to querying data over a GraphQL endpoint created with GraphDB, as shown in Creating a GraphQL interface from GraphQL schema shapes above, the GraphQL schema generated by GraphDB lets you use GraphQL mutations to add, update, and delete data on the server.

Note

The Create new user section of the GraphDB documentation describes how you can control GraphQL write access globally and for individual users.

The GraphiQL tool available on GraphDB’s GraphQL Playground gives you a visual interface to create both queries and mutations of the data behind your GraphQL endpoint:

_images/add-new-query-mutation.png

Once you pick Mutation from the Add new field, GraphiQL offers you a choice of templates to create, delete, or update data for each of the available types:

_images/mutationTemplateChoices.png

The following shows a create_Employee update operation in GraphiQL that creates a new instance of the Employee type by giving it a new id value and values for each of its fields. The lower half of the request specifies the data that should be returned so that we can confirm that the instance was created as planned: the values of the newly-created instance. On the right, we see that after executing the operation, the instance was created:

_images/createEmployeeMutation.png

Because GraphDB’s GraphQL interface provides access to the RDF data in the underlying repository, the Employee instance created by the update operation is then stored as a set of triples there, as we can see from this SPARQL query:

_images/sparqlQueryOfNewInstance.png

The create_Employee example above specified a hard-coded id value to use for the new instance. If you don’t specify an ID value for a new instance, the GraphQL schema creation will automatically generate one by appending a unique hexadecimal value to a base URI whose default value is http://example.org/resource/. You can reset the base URI of generated IDs by assigning an IRI to the empty prefix. In Turtle, that would look like this:

@prefix : <http://custom-iri.com/some/path/> .

When generating new IDs, you can use alphanumeric reference identifiers to generate IDs that link from one new object to another. These must be defined in a create operation at root or nested level. In the following, the first part of the query on the left creates an Address instance with “::1” as the ID value. The second part creates an Employee instance with { ids: ["::1"]} as the value of its address field. In the results of the mutation operation on the right, we see that the ID generated for the new address instance (ending with “65f8”) is the ID of the new employee’s address:

_images/creationMutationWithRefIDs.png

To update existing data using an update mutation, provide the IDs of the instances you want to modify and specify the fields to be updated along with their new values. The following example updates the givenName value of the Employee instance that was created above. Note that the ID value is specified inside of square brackets because you can submit a list of IDs to update. Like the mutation that originally created this employee’s instance, this update mutation also specifies field values to return, including special affected_count and affected_objects fields to show us what exactly got affected by the mutation. You can see the results on the right.

_images/updateEmployeeMutation.png

A delete operation is similar to an update, because the request includes a list of one or more instance IDs to act on, but that’s all you need. You can also optionally include the special affected fields in the return portion of the request to find out which data was affected. The mutation below deletes the instance that was created and updated in the previous two examples.

_images/deleteEmployeeMutation.png

Generating an endpoint from SHACL using the Star Wars dataset

This example uses data describing Star Wars movies, characters, planets and vehicles. It shows how to generate a GraphQL endpoint from SHACL shapes and use it to perform simple queries in the GraphQL Playground.

Prerequisites

Before you go through this example, download the starwars-data.ttl dataset and import it into a new repository called star-wars. Then import the swapi-shapes-ex1 shapes and import them into a named graph in the same repository.

Generate an endpoint from named graph

Once you have imported your data and connected to the star-wars repository:

  1. Go to GraphQL ‣ Endpoint Management, then select New endpoint

  2. Select OWL Ontologies/SHACL Shapes:

    • Under Endpoint ID, provide a unique name for the endpoint. This example uses star-wars.

    • Under Vocabulary prefix, select voc.

    • You can also provide a short Endpoint description.

  3. Choose Select one or more graphs to move the graph from Available (not included) to Included for generation.

  4. Click on icon-fa-circle-plus next to the name of your graph.

    Tip

    Since the repository should contain only one named graph at this point, you can also click on Add all instead.

  5. Select Next to move to the next screen. For the purposes of this example, leave all configurations on that page at their default values.

  6. Select Next, then Create endpoint.

Once GraphDB finishes creating the endpoint, you can either navigate to GraphQL ‣ GraphQL Playground, or directly select the name of the repository to load it into the GraphQL Playground.

See also

Executing simple queries in the GraphQL Playground

Once you have created your endpoint, you can use it to explore your data using GraphQL queries. Navigate to GraphQL ‣ GraphQL Playground, and make sure that the star-wars endpoint is selected from the top-down menu at the top right of the GraphQL Playground.

Note

You can explore the GraphQL schema through the icon-graphql-docs Documentation Explorer and icon-graphql-graphiql-explorer GraphiQL Explorer. Note that the types and their properties in your endpoint correspond to the SHACL shapes.

First, let’s get a list of all characters in Star Wars, ordered by height in descending order. Paste this query into the Query editor, then select icon-graphql-execute to execute the query:

query charactersOrderedByHeight {
  character(orderBy: {height: DESC}) {
    gender
    label {
      value
    }
    id
    height
  }
}

This query should return a result that begins with:

{
  "data": {
    "character": [
      {
        "gender": "male",
        "label": [
          {
            "value": "Yarael Poof"
          }
        ],
        "id": "https://swapi.co/resource/quermian/57",
        "height": "264.0"
      },
      {
        "gender": "male",
        "label": [
          {
            "value": "Tarfful"
          }
        ],
        "id": "https://swapi.co/resource/wookiee/80",
        "height": "234.0"
      },
      {
        "gender": "male",
        "label": [
          {
            "value": "Lama Su"
          }
        ],
        "id": "https://swapi.co/resource/kaminoan/72",
        "height": "229.0"
      },

      ...

However, the list of all characters in this repository is rather extensive. If you wish, you can instead query for a smaller set of characters — such as a query that will return only the characters that appear in Star Wars Episode IV: A New Hope, and limit the results to the first five characters:

query allCharactersInANewHope {
  character(limit: 5, where: {film: {ID: "https://swapi.co/resource/film/1"}}) {
    id
    label {
      value
    }
  }
}

Which should return the following:

{
  "data": {
    "character": [
      {
        "id": "https://swapi.co/resource/droid/2",
        "label": [
          {
            "value": "C-3PO"
          }
        ]
      },
      {
        "id": "https://swapi.co/resource/droid/3",
        "label": [
          {
            "value": "R2-D2"
          }
        ]
      },
      {
        "id": "https://swapi.co/resource/droid/8",
        "label": [
          {
            "value": "R5-D4"
          }
        ]
      },
      {
        "id": "https://swapi.co/resource/wookiee/13",
        "label": [
          {
            "value": "Chewbacca"
          }
        ]
      },
      {
        "id": "https://swapi.co/resource/rodian/15",
        "label": [
          {
            "value": "Greedo"
          }
        ]
      }
    ]
  }
}