API Extensions

Flow Operations

Operations are single steps in a Flow - the no-code automation tool part of Directus Automate.

Operations are single steps in a Flow - the no-code automation tool part of Automate.

An operation being created in a "New Subscription" flow

This extension type is loaded into the Directus process. They can use the provided services exported by the @directus/extensions-sdk package and can be written in JavaScript or TypeScript.

Operations have two entrypoints - one for the Data Studio, and one for the server process when the flow is run.

App Entrypoint

The app.js or app.ts file contains the configuration for the appearance and user-provided options of the operation.

Entrypoint Example

export default {
    id: 'custom',
    name: 'Custom',
    icon: 'box',
    description: 'This is my custom operation!',
    overview: ({ text }) => [
        {
            label: 'Text',
            text: text,
        },
    ],
    options: [
        {
            field: 'text',
            name: 'Text',
            type: 'string',
            meta: {
                width: 'full',
                interface: 'input',
            },
        },
    ],
};

Options

OptionDescription
idA unique identifier for this extension.
nameThe displayed name for this panel in the Data Studio.
iconAn icon name from the Google Material Icons set. Supports filled and outlined variants.
descriptionA description of this panel shown in the Data Studio. Maximum 80 characters.
overviewAn overview that will be shown on the operation's tile. Can be either a function that receives the options of the operation and returns an array of objects containing label and text or a dedicated Vue component.
optionsThe options of your operation. Can be either an options object or a dedicated Vue component.
Unique Identifiers
The extension id must not conflict with other extensions, so consider prefixing with author name.

API Entrypoint

The api.js or api.ts file contains the logic for the operation. It runs a handler function with the data passed from the App Entrypoint options.

Entrypoint Example

This example assumes there is an object with a name of text in the App Entrypoint options.

export default {
    id: 'custom',
    handler: (options) => {
        console.log(options.text);
    },
};
The id in both the app and the api entrypoint must be the same.

Handler Function

The handler function is called when the operation is executed. It must return a value to trigger the resolve anchor or throw with a value to trigger the reject anchor. The returned value will be added to the data chain.

The handler function receives options and context. options contains the operation's option values, while context has the following properties:

PropertyDescription
servicesAll API internal services.
databaseKnex instance that is connected to the current database.
getSchemaAsync function that reads the full available schema for use in services.
envParsed environment variables.
loggerPino instance.
dataObject containing the raw data returned by the previous operations.
accountabilityInformation about the current user received by the trigger.

Sandboxed Operations

TypeScript

You can import the SandboxOperationConfig type from directus:api to type the register function's context object:

/// <reference types="@directus/extensions/api.d.ts" />
import type { SandboxOperationConfig } from "directus:api";

const operation: SandboxOperationConfig = {
    id: 'custom',
    handler: (options) => {
    },
};

export default operation;

The handler function receives the options object of the current flow.

Learn more about the Directus sandbox for API extensions.

Using Directus Internals

To access systems like permission checks and your collections, you can use internal Directus services, available through an API extension's context parameter.

Learn more about using internal Directus services.

Error Handling

To create errors in API extensions, you can utilize the @directus/errors package which is available to all extensions without installation.

import { createError } from '@directus/errors';

const ForbiddenError = createError('FORBIDDEN', "You don't have permissions to see this.", 403);

throw new ForbiddenError();