GraphQL
ArcadeDB Server supports a subset of the GraphQL specification. Please open an issue or a discussion on GitHub to increase the support for GraphQL.
If you’re using ArcadeDB as embedded, please add the dependency to the arcadedb-graphql library.
If you’re using Maven include this dependency in your pom.xml file.
<dependency>
<groupId>com.arcadedb</groupId>
<artifactId>arcadedb-graphql</artifactId>
<version>26.5.1</version>
</dependency>
GraphQL is supported in ArcadeDB as a query language engine. This means you can execute a GraphQL command from:
-
Java API by using the non-idempotent
.command()and the idempotent.query()API by using"graphql"as language. Example:Resultset resultset = db.query("graphql", "{ bookById(id: "book-1"){ id name authors { firstName, lastName } }"); -
HTTP API by using
/commandand/querycommands and"graphql"as language -
Postgres Driver by prefixing with
{graphql}your query to execute. Example:{graphql}{ bookById(id: "book-1"){ id name authors { firstName, lastName } }
Type definition
GraphQL requires to define the types used. If you’re using the Document Model and links to connect documents, then you can map 1-1 the GraphQL type to ArcadeDB type. Example:
type Book {
id: ID
name: String
pageCount: Int
authors: [Author]
}
If you’re using a Graph Model for your domain, then you need to declare with a GraphQL directive how the relationship is translated on the graph model.
In the example below, the authors is a collection of Author retrieved by looking at the incoming (direction: IN) edges of type "IS_AUTHOR_OF" (type: "IS_AUTHOR_OF"):
type Book {
id: ID
name: String
pageCount: Int
authors: [Author] @relationship(type: "IS_AUTHOR_OF", direction: IN)
}
| Directives can be defined on both types and queries. Directives defined in queries override any directives defined in types, only for the query execution context. |
You can define your model incrementally and apply it to the current database instance by executing a command containing the type definition. Example by using Java API (but the same by using HTTP Command API):
String types = "type Query {" +
" bookById(id: ID): Book" +
"}" +
"type Book {" +
" id: ID" +
" name: String" +
" pageCount: Int" +
" authors: [Author] @relationship(type: \"IS_AUTHOR_OF\", direction: IN)" +
"}" +
"type Author {" +
" id: ID" +
" firstName: String" +
" lastName: String" +
"}";
database.command("graphql", types);
With this example the types Book and Author are defined together with the query bookById.
You can add new types or replace existing types by just submitting the type(s) again.
The GraphQL module will update the current definition of types.
| This definition is not saved in the database and must be declared after the database is open, before executing any GraphQL queries. |
Query arguments
Query fields can declare arguments of the standard GraphQL scalar types: ID, String, Int, Float and Boolean.
Example:
type Query {
books(inStock: Boolean, rating: Float): [Book]
}
type Book {
id: ID
name: String
inStock: Boolean
rating: Float
}
ResultSet resultSet = database.query("graphql", "{ books(inStock: true, rating: 4.5) { name } }");
A query field can also be declared without any argument, for example to list every record of a type:
type Query {
allBooks: [Book]
}
Argument values are passed to the database as parameters, never written into the generated query text, so a value
containing quotes or backslashes is always treated as data.
The standard GraphQL escape sequences (\", \\, \/, \b, \f, \n, \r, \t and
\uXXXX) are decoded, so this matches a book whose name really contains a line break:
{ bookByName(name: "Line one\nLine two") { id } }
The where argument
An argument named where is reserved: its value is used as the SQL condition of the generated query instead of being
compared against a property.
type Query {
books(where: WHERE): [Book]
}
ResultSet resultSet = database.query("graphql", "{ books( where: \"name = 'Mr. brain'\" ) { name } }");
Query variables
A query can declare variables and receive their values at execution time, so the same query text can be reused with different values:
query($name: String) {
bookByName(name: $name) { id name }
}
ResultSet resultSet = database.query("graphql", "query($name: String) { bookByName(name: $name) { id name } }",
"name", "Harry Potter and the Philosopher's Stone");
From the HTTP API the variables are the request parameters, and from the Postgres Driver they are the query parameters.
A variable can declare a default value, used when no value is passed:
query($name: String = "Mr. brain") { bookByName(name: $name) { id } }
Variables can also be used in the arguments of a directive written in the query:
query($edge: String) { bookById(id: "book-1") { authors @relationship(type: $edge, direction: IN) { lastName } } }
The value passed must match the type the variable is declared with, otherwise the query is rejected:
-
Intaccepts a whole number in the 32-bit range -
Floataccepts any number, but notNaNor infinity -
Booleanaccepts only a boolean,Stringonly a string -
IDaccepts a string or a whole number of any size -
any other type name (a custom scalar, an enum, a list) is passed through unchecked
A variable declared with ! (for example $name: String!) must receive a value, and that value cannot be null.
A variable used but never declared is an error, as is a variable used for the where argument.
Commas between variable declarations are not supported yet: write query($a: String $b: Int), not
query($a: String, $b: Int).
|
Field aliases
A selection can rename a field with the standard GraphQL alias syntax alias: field.
The alias becomes the key of the field in the result, while the underlying field is resolved normally.
Example:
{ bookById(id: "book-1")
{
title: name
authors {
first: firstName
lastName
}
}
}
This returns title (instead of name) and first (instead of firstName) as the result keys.
The top-level query field itself can also be aliased, including when it takes arguments:
{ myBooks: books(inStock: true) { name } }
Supported directives
Directives can be defined on both types and queries. Directives defined in queries override any directives defined in types, only for the query execution context.
@relationship
Applies to: Query Field and Field Definition
Syntax: @relationship([type: "<type-name>"] [, direction: <OUT|IN|BOTH>])
Where:
-
typeis the edge type, optional. If not specified, then all the types are considered -
directionis the direction of the edge, optional. If not specified, then BOTH is used
Example:
friends: [Account] @relationship(type: "FRIEND", direction: BOTH)
Relationships can be traversed at any depth, each level being resolved against its own type. The query below walks from a book to its authors, then back to every book each author wrote:
{ bookById(id: "book-1")
{
name
authors {
lastName
wrote { name }
}
}
}
@sql
Applies to: Query Field and Field Definition
Syntax: @sql( statement: <sql-statement> )
Executes a SQL query. The query can use parameters passed at invocation time.
Example of definition of a query using SQL in GraphQL:
bookByName(bookNameParameter: String): Book @sql(statement: "select from Book where name = :bookNameParameter")
Invoke the query defined above passing the book name as parameter:
ResultSet resultSet = database.query("graphql", "{ bookByName(bookNameParameter: \"Harry Potter and the Philosopher's Stone\")}"));
@gremlin
Applies to: Query Field and Field Definition
Syntax: @gremlin( statement: <gremlin-statement> )
Executes a Gremlin query. The query can use parameters passed at invocation time.
Example of definition of a query using Gremlin in GraphQL:
bookByName(bookNameParameter: String): Book @gremlin(statement: "g.V().has('name', bookNameParameter)")
Invoke the query defined above passing the book name as parameter:
ResultSet resultSet = database.query("graphql", "{ bookByName(bookNameParameter: \"Harry Potter and the Philosopher's Stone\")}"));
@cypher
Applies to: Query Field and Field Definition
Syntax: @cypher( statement: <cypher-statement> )
Executes a Cypher query. The query can use parameters passed at invocation time.
Example of definition of a query using Cypher in GraphQL:
bookByName(bookNameParameter: String): Book @cypher(statement: "MATCH (b:Book {name: $bookNameParameter}) RETURN b")
Invoke the query defined above passing the book name as parameter:
ResultSet resultSet = database.query("graphql", "{ bookByName(bookNameParameter: \"Harry Potter and the Philosopher's Stone\")}"));
@rid
Applies to: Query Field and Field Definition
Syntax: @rid
Mark the field as the record identity or concepts/basics.adoc#rid.
Example:
{ bookById(id: "book-1")
{
rid @rid
id
name
authors {
firstName
lastName
}
}
}