title | perex | date | author | preferredLang |
---|---|---|---|---|
GraphQL |
GraphQL is an open-source data query and manipulation language for APIs, providing a powerful alternative to REST by
allowing clients to specify exactly what data they need, reducing over-fetching and under-fetching of data. Developed
by Facebook in 2012 and open-sourced in 2015, it enables declarative data fetching where the client can ask for what
it needs and get exactly that.
|
21.3.2023 |
Lukáš Hornych |
graphql |
The main idea behind our GraphQL API implementation is that the API schema is dynamically generated based on
evitaDB's internal schemas. This means that users only see the data they
can actually retrieve. They do not see some generic strings of names. For example, if you have defined in evitaDB an
entity called Product
with attributes code
and name
, the GraphQL API allows you to query only these two attributes
like this:
getProduct {
attributes {
code
name
}
}
and on top of that, they will have data types that are equivalent to the ones specified in evitaDB, and not some generic ones.
- catalog data API
-
A GraphQL API instance that provides ways to query and update actual data (typically entities and related data)
of a single catalog.
URL pattern: `/gql/{catalog-name}` </dd> <dt>catalog schema API</dt> <dd> A GraphQL API instance that provides ways to fetch and modify the internal structure of a single catalog. URL pattern: `/gql/{catalog-name}/schema` </dd> <dt>system API</dt> <dd> A GraphQL API instance that provides ways to manage evitaDB itself. URL pattern: `/gql/system` </dd> </dl>
There isn't a single GraphQL API instance for the whole evitaDB instance. Instead, each evitaDB catalog has its own GraphQL API (actually each catalog has two GraphQL API instances, but more on that later) on its own URL with data only from that particular catalog. In addition, there is one another GraphQL API instance that is reserved for evitaDB administration (e.g. creating new catalogs, removing existing catalogs) called system API.
Each GraphQL API instance URL starts with
/gql
, followed by the URL-formatted catalog name for specific catalog APIs, or with the reservedsystem
keyword for the above-mentioned system API. For each catalog there is a catalog data API located at the/gql/{catalog name}
base URL and a catalog schema API located at the/gql/{catalog name}/schema
URL. The catalog data API is used to retrieve and update the actual data of a given catalog. The catalog schema API is more of an "introspection" API, as it allows users to view and modify internal evitaDB schemas, which in turn affects the GraphQL API schema.Each GraphQL API instance supports only
POST
HTTP method for executing queries and mutations.Each GraphQL API instance supports standard introspection capabilities for GraphQL schema reconstruction. On top of that, each instance supports fetching reconstructed GraphQL schema in DSL format using
GET
HTTP request on the instance URL. For example, to fetch the GraphQL schema of thefashion
catalog, you can issue the following HTTP request:GET /gql/fashion
We are aware that this implementation is not the right way of using
GET
method according to the GraphQL spec. However, we opted for this implementation because we use the same approach for fetching the OpenAPI specifications of REST API. Also, we don't plan to support executing queries and mutations usingGET
method anyway, because it involves unnecessary escaping of the query string and so on.Suppose you have catalogs
fashion
andelectronics
. evitaDB would expose the following GraphQL API instances, each with its own relevant GraphQL schema:/gql/fashion
- a catalog data API to query or update the actual data of thefashion
catalog/gql/fashion/schema
- a catalog schema API to view and modify the internal structure of thefashion
catalog/gql/electronic
- a catalog data API to query or update the actual data of theelectronic
catalog/gql/electronic/schema
- a catalog schema API to view and modify the internal structure of theelectronic
catalog/gql/system
- the system API to manage evitaDB itself
A single catalog data API for a single catalog contains only a few types of queries and mutations, but most of them are "duplicated" for each collection within that catalog. Each query or mutation then takes arguments and returns data specific to a given collection and its schema.
In addition to user-defined collections, there is a "virtual" simplified collection for each catalog in the GraphQL API called
entity
that allows users to retrieve entities by global attributes without knowing the target collection. However, theentity
"collection", has only limited set of queries available.A single catalog schema API for a single catalog contains only basic queries and mutations for each collection and parent catalog to retrieve or change its schema.
There is nothing special about the system API, just a set of basic queries and mutations.
evitaDB is shipped with its own query language, for which our GraphQL API has its own facade. The main difference between these two is that the evitaDB's original language has generic set of constraints and doesn't care about concrete collection data structure, where the GraphQL version has the same constraints but customized based on collection data structure to provide concrete available constraint for defined data structure.
This custom version of the query language is possible because in our GraphQL API, the query language schema is dynamically generated based on internal collection schemas to display only constraints that can actually be used to query data (which also changes based on context of nested constraints). This also provides constraint arguments with data types that match the internal data. This helps with the self-documentation because you don't necessarily need to know about the domain model, since most of GraphQL IDEs will auto-complete the available constraints from the GraphQL API schema.
Syntax of query and constraints
Our GraphQL APIs conform to the official specification, thus it can be used like any other regular GraphQL API, i.e. with standard tools. However, below are our recommendations for tools etc. that we use at evitaDB.
We've developed our own GUI tool called evitaLab which supports GraphQL with usefull tools (e.g. data visualisations). It also has other useful tools for exploring evitaDB instances, not just using GraphQL API. Therefore, this is our recommened chose of IDE for our APIs.
However if you want to use a generic GraphQL tool, we have recommendations for that too. During development, we have come across and tried several tools for consuming GraphQL APIs, but there are only a few that we can recommend.
For a desktop IDE to test and explore GraphQL APIs, the Altair client proved to be a great help. It is a fantastic desktop client for GraphQL APIs with excellent code-completion and a nice API schema explorer. You can also use a more general HTTP desktop client like Insomnia, which also features GraphQL tools with an API schema explorer, albeit limited. Postman can also be used. Typically, you can even use GraphQL plugins in your code IDE, e.g. the IntelliJ IDEA offers the GraphQL plugin that nicely integrates into your workflow, although without an API documentation like other standalone IDEs offer.
If you are looking for a web-based client that you can integrate into your application, there is the official lightweight GraphiQL, which provides all the basic tools you might need.
The basic idea of using the IDE is to first fetch the GraphQL API schema from one of the above-mentioned URLs that are exposed by evitaDB. Then explore the API schema using the IDE's docs/API schema explorer and start typing a query or mutation to send to the server. In case of e.g. the Altair you don't even need to explore the API schema manually because Altair has, like many others, has a code-completion in its editor based on the retrieved API schema.
You can find all the available libraries on the official GraphQL website for you to choose from for your own client language. Some can even generate classes/types based on the API schema for you to use in your codebase.