Use GEARS API - XLRIT/gears GitHub Wiki

1. Table of content

2. Introduction

The GEARS runtime uses GraphQL as its API. This document assumes basic knowledge on using GraphQL, mainly queries (getting data) and mutations (changing data).

Also note that this document does not explain how to call the API from say JavaScript, Java, or any existing programming language. You'll have to figure that out on your own. But don't worry. the internet is filled with a ton of examples for different languages.

And the last thing to say before we start is that it is common to use query variables. We'll only show how this works in the first example. However, to make this document easy to read, we will not use this approach in the remainder of this document.

3. Prerequisites

  1. You have at least one case up and running as described in Home. We'll use the leave_of_absence demo case as an example.
  2. You have installed the GraphQL Playground or an equivalent GraphQL development environment.
  3. In the current version of the GEARS runtime (0.88) it is required to add the following to the application.yml file (if not the GraphQL Playground will not be able to communicate with the GraphQL API of the runtime, due to CORS):
graphql:
  servlet:
    cors:
      allowed-origins:    '*'
      allowed-methods:    '*'
      allowed-headers:    '*'
      allow-credentials:  false

4. How to use the GEARS API

4.1. Get GEARS GraphQL docs

For the most part GraphQL API's are self documented. The easiest way to get this documentation is to enter the GraphQL URL ENDPOINT when you start the GraphQL playground (in short called playground from now on). The URL ENDPOINT of the GEARS API is:

http://localhost:8080/graphql

When you have entered this in the playground you should see vertical tabs (DOCS and SCHEMA) on the right of the screen, which you can expand and browse:

docs_and_schema

Although the documentation helps, it is for now only a limited reference. So don't spent too much time on reading this right now, but quickly go to the next paragraphs.

4.2. Login

The following mutation will log a user in based on username and password:

mutation { login(username: "demo", password: "demo") }

When using query variables this query would look like this:

mutation LoginMutation($username: String!, $password: String!) {
    login(username: $username, password: $password)
}

In the playground you would have provide the values for $username and $password by entering them as JSON key value pairs under QUERY VARIABLES. In this example you would enter this text:

{ "username": "demo", "password": "demo"}

If you run this query in the playground, the result looks a bit like this:

login

This means you now have received a "Bearer token" that can be used to identify a logged in user. In this example the Bearer token is a long string starting with eyJ0e... and ends with _taD4M

You can put this Bearer token in the HTTP header so the GEARS GraphQL API knows who the logged in user is. Just click on HTTP HEADERS and enter the token as in the following example:

{ "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkZW1vIiwiZm9vIjoiYmFyIiwiaXNzIjoiWExSSVQiLCJpYXQiOjE2MTI1MjcwMzd9.OIb7-HLjiPq5lAOm7q2ua-P-0m8rY3J95VqlhIf3gSo"}

In the next paragraphs I will assume you have done so.

Note that: the demo user is authorized for everything. There are also users that can only start processes and perform tasks for certain roles.

user role
employee1 EMPLOYEE
employee2 EMPLOYEE
manager1 MANAGER
manager2 MANAGER
customer1 CUSTOMER
customer2 CUSTOMER
aanvrager1 AANVRAGER
beoordelaar1 BEOORDELAAR

In the process diagram (see example below) you see the role in the task name. For instance: in the task Task 1 From EMPLOYEE: ... the role is EMPLOYEE. As this is the first task of a process, only users with that role are authorized to list and start this his/hers processes.

4.3. Get list of startable processes

Getting a list of startable processes is an example of a GraphQL query (get data). Below is an example of this query which I have named GetProcessDefinitions. Once again, you can name them as you like. Besides this, one of the benefits of GraphQL is that you can also choose which fields you would like to retrieve, so if you only need key, name and description, than you only need to provide these attribute names.

query GetProcessDefinitions {
    processDefinitions {
    id
    key
    name
    description
    hasStartForm
    }
}

You should get a list of processes this user can start. For instance like this:

{
  "data": {
    "processDefinitions": [
      {
        "id": "loa.absence.request:1:01FXAJBTR245JSATJNEJMTZDY0",
        "key": "loa.absence.request",
        "name": "Request absence",
        "description": "Request a leave of absence",
        "hasStartForm": false
      }
    ]
  }
}

Of course you should only get a list of process definitions that can be started by the logged in user. For this example case you can try this by first logging in as manager1, then put the bearer token in the HTTP HEADERS as described above, and then try to run the GetProcessDefinitions query again. You will see that you will not get the process called "Request absence".

4.4. Start a process

The previous query resulted in a value called "key" with a value of "loa.absence.request". The following query can be used to start that process.

mutation {  startProcessByKey(key:"loa.absence.request") { id, tasks { id } }  }

Note that this call also explicitly asks for extra data, such as the id of the started process (called a "process instance") all tasks that are started as a result of starting this process and for each task, its id. The result would look like this:

{
  "data": {
    "startProcessByKey": {
      "id": "01FXAKFKQPAXHVBV71FCMTK7KB",
      "tasks": [
        {
          "id": "01FXAKFKQQNX56DGB8H9T4E17K"
        }
      ]
    }
  }
}

You have now started a process. The "id" of the first tasks (in this example just one). This task "id" can be used to claim and open this task, which we will do in the next paragraph.

4.5. List of tasks

Consistent with the GEARS Frontend you can retrieve a list of two types of tasks:

  • Assigned tasks: tasks that are already assigned to the logged in user.
  • Group tasks: tasks that the logged in user is authorized to start (claim and open).

Below are the matching queries to get these lists:

query {
    assignedTasks {
        id
        name
        subject
        assignee
        allowedRoles
        processDefinition { name }
    }
}

and

query  {
    groupTasks {
        id
        name
        subject
        assignee
        allowedRoles
        processDefinition { name }
    }
}

4.6. Claim and open a task.

The process flow framework that the GEARS runtime uses has a 2 phase approach to actually start a task:

  1. Claim a task: which is basically assigning a specific user to a task. In this case the logged in user. If you claim a task, the task moves from Group tasks to the Assigned tasks of the user who has claimed it.
  2. Open a task: which is getting the info of a task to inform the user how to perfom the task.

This is an example of claiming a task:

mutation {  claimTask(id: "01FXAJS4EVZ5D54M6AE52SD4TB")  }

And right after that a task can be "opened" (read) with the same id like this:

query {
    task(id:"01FXAJS4EVZ5D54M6AE52SD4TB") {
        name
        documentation
        form
    }
}

Below is an example of the second task in the leave of absence case.:

{
  "data": {
    "task": {
      "name": "Task 2 for Manager",
      "documentation": {
        "nr": 2,
        "for": "Manager",
        "structure": [
          {
            "kind": "input",
            "name": "decision",
            "parent": "LEAVE_REQUEST"
          },
          {
            "kind": "input",
            "name": "reason",
            "parent": "LEAVE_REQUEST"
          }
        ]
      },
      "subject": "(none)",
      "form": {
        "fields": [
          {
            "path": "decision",
            "name": "decision",
            "baseName": "decision",
            "parentName": "LEAVE_REQUEST",
            "type": "TEXT",
            "label": "Decision",
            "optional": false,
            "labeled": false,
            "isLabeled": false
          },
          {
            "path": "reason",
            "name": "reason",
            "baseName": "reason",
            "parentName": "LEAVE_REQUEST",
            "type": "TEXT",
            "label": "Reason",
            "optional": false,
            "labeled": false,
            "isLabeled": false
          }
        ],
        "values": {
          "decision": "approved",
          "reason": null,
          "__basedOn": {
            "__kind": "tuple",
            "Requestor": "Danny Demo",
            "Type": "sickness",
            "Start": "2022-03-04",
            "End": "2022-04-01"
          }
        },
        "aux": {
          "decision": {
            "choices": [
              {
                "value": "approved",
                "label": "approved"
              },
              {
                "value": "rejected",
                "label": "rejected"
              }
            ]
          },
          "reason": {}
        }
      }
    }
  }
}

Most don't need explanation, but these may:

Field Explanation
documentation this is a but of JSON that explains for which type of user (role) this task is and what this user has to enter (input).
form this defines the form the user would normally be presented with. It contains the fields, from which entity they are part of (e.g. LEAVE_REQUEST), their labels on the screen and their types (e.g. TEXT or DATE, etc.).
values this contains either default values for input fields but also a __basedOn which contains the read only information the user needs to be able to enter the input fields.
aux this defines which choices the users can choose from for each field (only filled if needed).

4.7. Submit a task and handle follow up tasks

Sumitting a task is done with the submitTask mutation. This mutation requires 2 parameters:

  • id: which is the task id if the task you want to submit. For instance the same id you used to open the task.
  • values: this coincides with the values key which you got when opening a task (as described previously) but of course now you can fill in the values with actual values.

Below is an example of submitting a leave of absence request with a type set to holiday and a start of the 13th of February 2021 and a end of the 25th of February 2021.

mutation { submitTask( id:     "01FXAPMNWWM6WJ7X1E61T3N6VE", 
                       values: {   decision:  "rejected",
                                   reason: "Too many Corona cases"
                               } 
                     ) { __typename 
                        ... on ProcessInstance { id, assignedTasks { id } }
                        ... on ProcessInstanceEnded { id }
                        ... on InputErrors { errors { path, name, type, label, value, status, message } }
                       }
         }

A possible response could look like this:

{
  "data": {
    "submitTask": {
      "__typename": "ProcessInstanceEnded",
      "id": "01FXJZKTX718J04G9PGZNPN603"
    }
  }
}

As you may already gave guessed, the __typename and what follows is a typical GraphQL concept of a reponse that may vary depending on the situation. Apparently there are 3 types of results, which suggest 3 types of situations.

Response type / situation Explanation
ProcessInstance Process has not yet ended and may even produce 0 or more assignedTasks as follow up task for this user.
ProcessInstanceEnded The process has ended.
InputErrors The task could not be submitted succesfully due to errors. Each error contains information about the field that has been filled incorrectly as well as a message saying what the error was (e.g. Field "Start" should be filled with a data value.).

Good to know:

  • the values key looks almost identical to the result you get back when opening a task as described in the previous section. The only difference is that in that result the keys are surrounded with double quotes ("...") while when submitting a task the keys do not have double quotes around them.
  • Interestingly enough, you could use the GEARS Frontend to fill in the task by hand and than press the Save button instead of the Submit button. If you would then open the same task but with GrapQL you would see exactly how values should be filled. You simply need to remove the double quotes around the names of the keys and than you would have the exact value of the values key. Just try this and you will quickly see how this works. Even for more complex values when submitting tasks.