Creating actions

Introduction

An action is a GraphQL mutation. You have to define the GraphQL type of the arguments that the mutation accepts and the GraphQL type of its response.

To create an action, you have to:

  1. Define the mutation
  2. Define the required types
  3. Create a handler

For example, let’s start with a basic mutation that accepts a list of numbers and returns their sum. We’ll call this mutation addNumbers.

Step 0: Setup

There is no setup required for defining actions via the console.

Download the latest pre-release CLI version from the releases page

You can either get started with an existing project or create a new project.

For a new project

hasura init

This will create a new project. You can set up your GraphQL engine endpoint (and admin secret if it exists) in the config.yaml.

Run hasura metadata export so that you get server’s metadata into the metadata/ directory.

For existing projects

Actions are supported only in the v2 config of the CLI. Check the config.yaml of your Hasura project for the version key.

If you are in version: 1, actions commands are not supported. Upgrade to version 2 by running:

hasura scripts update-config-v2

Run hasura metadata export so that you get server’s metadata into the metadata/ directory.

Step 1: Define your mutation and associated types

Go to the Actions tab on the console and click on Create. This will take you to a page like this:

Console action create

Define the action as follows in the Action Definition editor.

type Mutation {
  addNumbers (numbers: [Int]): AddResult
}

In the above action, we called the returning object type to be AddResult. Define it in the New types definition as:

type AddResult {
  sum: Int
}

To create an action, run

hasura actions create addNumbers

This will open up an editor with metadata/actions.graphql. You can enter the action’s mutation definition and the required types in this file. For your addNumbers mutation, replace the content of this file with the following and save:

type Mutation {
  addNumbers (numbers: [Int]): AddResult
}

type AddResult {
  sum: Int
}

The above definition means:

  • This action will be available in your GraphQL schema as a mutation called addNumbers
  • It accepts an argument called numbers which is a list of integers.
  • It returns an output type called AddResult.
  • AddResult is a simple object type with a field called sum of type integer.

Step 2: Create the action handler

A handler is an HTTP webhook where you can perform the custom logic for the action. In this case, it is the addition of the numbers. NodeJS/Express code for this handler would look something like:

const handler = (req, resp) => {
  // You can access their arguments input at req.body.input
  const { numbers } = req.body.input;

  // perform your custom business logic
  // return an error or response
  try {
    return resp.json({
      sum: numbers.reduce((s, n) => s + n, 0)
    });
  } catch(e) {
    console.error(e)
    return resp.status(500).json({
      message: 'unexpected'
    })
  }
};

You can deploy this code somewhere and get URI. For getting started quickly, we also have this handler ready at https://hasura-actions-starter-kit.glitch.me/addNumbers.

Set the handler

Now, set the handler for the action:

Set the value of the handler field to the above endpoint.

Go to metadata/actions.yaml. You must see a handler like http://localhost:3000 or http://host.docker.internal:3000 under the action named addNumbers. This is a default value taken from config.yaml.

Update the handler to the above endpoint.

URL templating

To manage handler endpoints across environments it is possible to template the endpoints using ENV variables.

e.g. https://my-handler-endpoint/addNumbers can be templated to {{ACTION_BASE_ENDPOINT}}/addNumbers where ACTION_BASE_ENDPOINT is an ENV variable whose value is set to https://my-handler-endpoint

Step 3: Finish action creation

Hit Create.
Run hasura metadata apply.

Step 4: Try it out

In the Hasura console, head to the GraphiQL tab and try out the new action.

mutation MyMutation {
  addNumbers(numbers: [1, 2, 3, 4]) {
    sum
  }
}
mutation MyMutation { addNumbers(numbers: [1, 2, 3, 4]) { sum } }
{ "data": { "addNumbers": { "sum": 10 } } }

And that’s it. You have created your first action!