Flows

4 min read

Flows are the building blocks of your application. A flow defines the logic that executes when, for example, an HTTP request comes in. A simple example of this is given in the introduction.

A flow runs in a separate process inside a virtual environment. Each flow has a limited execution time of 30 seconds and a memory limit of 64MB. This is sufficient for processing API calls and simple cron jobs. Longer running processes are split into multiple smaller chunks.

Each flow contains at least a start and end block. More blocks can be added to define logic. The blocks have small circles on the left and right edges. These are the input and output pins, respectively. You can connect blocks by dragging output pins to input pins. When you do that, a dialog opens where you can define what data to use for the input. This is called the mapping.

Flow types

Different flow types exist for different use cases. This page describes the types currently available. More flow types will become available in the future.

HTTP endpoint

You can create a REST API using this flow type. A separate flow is created per endpoint, which is a combination of HTTP method and path, for example, "PUT /api/user/{id}" to update a user profile.

HTTP endpoint configuration

The path can contain dynamic parameters inside curly braces. Each parameter needs a type, which is either an integer, sting, or id referring to an object in the database. In the last case, the object is automatically loaded from the database; hence, the full object is available in the flow. Also, a 404 is returned automatically when the id is invalid.

The HTTP endpoint block needs an output schema. This is the definition of the HTTP response body.

Cron job

This flow type defines a scheduled task. You define the interval in its configuration. It can run at most every minute. When running once per hour, it is guaranteed that it runs every hour, but not exactly at what minute. A cron job has no input or output.

Incoming mail

This flow type is used to integrate with systems (or humans) that are able to send mail. In general, it is preferred to integrate by sending webhooks to a REST endpoint, but some systems do not support webhooks but can send mail. Each mail flow has its own email address, which you can find in the configuration of the start block.

The output of the start block contains the parsed mail message. You can easily extract text, subject, sender, and mail headers. Attachments are not included in this flow but can be received in scripts that you define later in the flow. The code to receive the attachment is:

const contents = await mail.readAttachment(messageId, filename);

You can find the messageId and filenames in the body.

Re-usable

A re-usable flow defines a block that you can add as a block to other flows. You define a name and its input schema in the start block's configuration. The output schema is defined in the end block's configuration. You can directly add the flow as a block in other flows.

Data in the flow

Each step in the flow manipulates a single JSON object. This is best understood with an example. Let's consider an HTTP endpoint flow. The start block has an output pin named "request". The - somewhat simplified - data it outputs is:

{
  "inputHeaders": {
    "content-type": "application/json",
    ...
  },
  "requestBody": {
    "title": "Test",
    ...
  }
}

We can connect this pin to a new block, for example the "Create Post" CRUD block (if we have a data table named "Post"). The expected input data and output data are as follows:

// Input:
{"post": {"title": "..."}}

// Output:
{"post": {"id": "...", "title": "..."}}

The mapping dialog allows us to match the flow data (coming from the start block's request pin) to the input of Create Post. We have to define this mapping manually. On the other hand, the output is automatically merged with the flow data. Therefore, the output of the Create Post block's "out" pin is:

{
  "inputHeaders": {
    "content-type": "application/json",
    ...
  },
  "requestBody": {
    "title": "Test",
    ...
  },
  "post": {
    "id": "...",
    "title": "..."
  }
}

The property name "post" is defined in the output schema of the Create Post block. It is possible that this property already exists. The last output will overwrite the existing property. This happens for example when you connect two subsequent Create Post blocks. If you need both values, you can rename one of them in the mapping dialog.