GraphQL API quick-start guide
In this guide we’ll look at a plugin named local_todo
(which is the plugin todo
in the local
directory) as an example.
- 1 What is GraphQL?
- 1.1 Concepts
- 1.2 Schema types
- 1.2.1 External schema
- 1.2.2 Internal schema
- 1.2.3 Mobile schema
- 2 Create an internal query
- 3 Create an internal mutation (e.q. create, update, delete)
- 3.1 Create the schema
- 3.1.1 Create the item’s type
- 3.1.2 Create the input types
- 3.1.3 Create the result type
- 3.1.4 Create the mutation
- 3.2 Create the backend
- 3.3 Run the Mutation
- 3.1 Create the schema
- 4 Using internal GraphQL in Tui components
- 5 Testing queries and mutations
What is GraphQL?
GraphQL is a way to get data from an API where you can ask for exactly what you need and nothing more. Totara uses GraphQL for i
Concepts
For a detailed explanation of GraphQL concepts, please see our https://totara.atlassian.net/wiki/spaces/~simonc/pages/119473875 documentation. However, if you just want to see the GraphQL API in action, please head straight to the Create an internal query section.
Schema types
In Totara, schemas are categorised based on their use cases. Each schema type - queries, mutations, types, etc. - follows specific rules about its availability and interactions with other schema types. Totara defines three primary schema types: external, internal, and mobile.
External schema
The external schema is used for defining APIs accessible to external systems. It serves as the ‘root’ schema since it can be accessed by other schemas.
External schemas are stored in the plugin's webapi/
directory. For example, in the local_todo
plugin, the external schema file would be located at:
server/local/todo/webapi/schema.graphqls
Internal schema
The internal schema, also referred to as ajax
in the codebase, is designed for internal client operations. It is isolated and not accessible to other schema types.
Internal schemas are stored in the plugin's webapi/ajax/
directory. For example, in the local_todo
plugin, the internal schema file would be located at:
server/local/todo/webapi/ajax/schema.graphqls
For more information, refer to Totara's developer documentation or check the guide below on creating an internal query.
Mobile schema
The mobile schema is tailored for APIs used by the Totara Mobile app.
Mobile schemas are stored in the plugin's webapi/mobile/
directory. For example, in the local_todo
plugin, the mobile schema file would be located at:
server/local/todo/webapi/mobile/schema.graphqls
Create an internal query
Create the schema
Create a
webapi
directory in your plugin directory. For example, for mylocal_todo
plugin, this would be in/server/local/todo/
.Under the
webapi
directory, create anajax
directory.Create a
schema.graphqls
file under theajax
directory.In
schema.graphqls
, let’s define thetodo_item
type by adding the following:This adds a new type with
id
,title
andcompleted_at
, which we will have access to when using this type.objectNo
Create the query
We’ll start off our APIs by creating a query to retrieve a list of the type todo_item
.
In
schema.graphqls
define the result we’ll get back from the query by defining the following type:Notice here we’ve used
!
in two places. This indicates the field is non-nullable. We’ve used this here to say that we always expect an array, by putting the exclamation mark on the outside of the array[...]!
. We also used it to to say that the elements of the array cannot be null[my_type!]
.Now we have the result defined, let’s define the query. We do this by extending the type
Query
and adding our query into it. Let’s do this:This defines that the query
local_todo_items
should return thelocal_todo_items_result
type we defined earlier.
Creating the persisted query
The persisted query is a definition of the query for the front-end component to import. We name this file the query name, minus the component name of the plugin we’re working with.
Persisted queries use .graphql
instead of the .graphqls
we used previously for the schema file.
Create the persisted query file in
webapi/ajax/items.graphql
with the following:
Create the backend
Now we need to create the PHP backend to handle the query.
First we’ll create the directory for the query resolver by creating the following directory:
/server/local/todo/classes/webapi/resolver/query
Now let’s create the query resolver class,
items.php
in the directory we just created:In this file we’ve defined the query resolve and we’re using the ORM of
local_todo
to return a list of items.Now we create the type resolver directory
/server/local/todo/classes/webapi/resolver/type/
and the type resolver for itemitem.php
in the directory:
Create an internal mutation (e.q. create, update, delete)
In this example we’ll create a mutation to update the title of a local_todo_item
.
Create the schema
Create a
webapi
directory in your plugin directory. For example, for mylocal_todo
plugin, this would be in/server/local/todo/
.Under the
webapi
directory, create anajax
directory.Create a
schema.graphqls
file under theajax
directory.
Create the item’s type
In schema.graphqls
, let’s define the todo_item
type by adding the following:
This adds a new type with id
, title
and completed_at
, which we will have access to when using this type.
Create the input types
Our mutation will take two input: one will be our item reference (which item we want to update) and the other will be the new item title.
Let’s start out with the input object to refer to an item. In
schema.graphqls
, let’s define thelocal_todo_update_item_reference
Notice the new input
keyword we used here. This is input object which defines what information we need from the client. In this case it’s just id
. For more information, see the GraphQL documentation:https://graphql.org/learn/schema/#input-object-types.
Now we’ll add the input object to retrieve the new title.
Create the result type
The result type will define what we’ll return from the mutation.
In
schema.graphqls
define the result type:
Create the mutation
Now we’ll create the mutation to update the title. We’ll name this local_todo_update_item
and extend the type Mutation. Similar to how we did this with Query.
In
schema.graphqls
, add the mutation:
Create the backend
Examples are simplified and use the ORM entity rather than the model for simplicity. Best practice would be to use the ORM model.
Now we need to create the PHP backend to handle the query.
First we’ll create the directory for the query resolver by creating the following directory:
/server/local/todo/classes/webapi/resolver/query
Now let’s create the query resolver class,
items.php
in the directory we just created:In this file we’ve defined the mutation resolver and we’re using the ORM entity of
local_todo
to update and return the item.Now we create the type resolver directory
/server/local/todo/classes/webapi/resolver/type/
and the type resolver for itemitem.php
in the directory:
Run the Mutation
If you haven’t already, please follow the Testing queries and mutations section to set up your developer environment.
The mutation to run would be:
Using internal GraphQL in Tui components
Please see our guide to creating your first component in Tui: Quick-start guide: Creating your first component. This guide covers how to create your first Tui component and also how to link it up to an GraphQL query.
Testing queries and mutations
To test your queries and mutations, please see our guide to using the developer GraphQL API: Making developer requests via a GraphQL client