Skip to content

Routing & Request Validation ​

When someone calls your API, Fluxify automatically figures out which workflow to run, checks the request data against your defined rules, and only then starts executing your logic. This page explains how that works and what your callers can expect to receive.

How Requests Are Matched ​

Every route you create in Fluxify has an HTTP method (like GET or POST) and a URL path (like /users/:id). When a request comes in, Fluxify matches it to the right workflow instantly.

  • If a match is found, the workflow runs.
  • If nothing matches, the caller gets a 404 response.

Path parameters like :id or :slug are captured automatically and made available inside your workflow.

Hot Reloading

Routes update in real time. When you create or change a route in the dashboard, the change takes effect immediately — no server restart needed.

Experimental CPU-Stall Timeout ​

Every route has a timeoutSeconds setting. It defaults to 30 seconds and can only be increased. The setting is carried with the compiled route whenever you save it, so a timeout change takes effect through the normal route hot reload path.

The timeout becomes active only when the project's experimental worker-timeout policy is enabled:

bash
curl -X PUT "http://localhost:8080/_/admin/api/v1/projects/<project-id>/settings/keys" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <access-token>" \
  -d '{"key":"experimental.workerTimeouts.enabled","value":"true"}'

This policy detects synchronous CPU stalls, such as an infinite loop in custom JavaScript. It does not time out a long asynchronous operation while the execution process remains responsive. When a CPU stall exceeds the configured route timeout, the in-flight connection is dropped and only the isolated execution process is replaced; the worker container continues receiving NATS hot updates.

When the policy is disabled (the default), no execution heartbeats or timeout tracking are created.

What Happens Before Your Workflow Runs ​

Before Fluxify executes a single block in your workflow, it runs through a quick validation pipeline:

  1. Match the route — find the right workflow for this request.
  2. Check the content type — make sure the caller sent a format this route accepts.
  3. Parse the request body — turn it into data your blocks can use.
  4. Validate the body — check it against your Body Schema (if set).
  5. Validate query parameters — check URL query strings against your Query Schema (if set).
  6. Validate path parameters — check URL path values against your Params Schema (if set).
  7. Run your workflow — only if everything above passed. If the route has middlewares, the ones set to run before it go first, and the ones set to run after it get the reply.

If any validation step fails, the workflow never runs and the caller immediately gets a clear error response.

Accepted Content Types ​

A route declares which body formats it accepts. New routes accept application/json only; choose more under Accepted content types when you create the route, or later in the route's Settings.

Content typeWhat your workflow receives
application/jsonThe parsed JSON value
application/x-www-form-urlencodedAn object of field names and text values
multipart/form-dataAn object of text fields plus any uploaded files
application/octet-streamThe raw binary body as a Blob, or a ReadableStream<Uint8Array> when the route uses Pipe request body as a stream
text/plainThe text as sent

For application/octet-stream, turn on Pipe request body as a stream under the body settings to hand getRequestBody() the live ReadableStream<Uint8Array> instead of collecting the bytes into a Blob. Nothing is buffered or size-limited by Fluxify in that mode, so pipe it straight to a file, S3, or another destination. Stream routes accept only application/octet-stream, have no body schema, and cannot be called with x-fluxify-reply: async.

A request in any other format — or in a format this particular route wasn't set up for — is rejected with 415 and the workflow never runs. GET and DELETE requests carry no body at all.

Bodies have a size limit

8 MB by default, and larger requests get a 413. See request body size.

Request Validation ​

Each route optionally has three schemas you can configure in the Schema Editor:

SchemaWhat It Validates
Body SchemaThe request body (POST, PUT): JSON, form fields, uploaded files or raw binary
Query SchemaURL query parameters (e.g. ?page=2&limit=10)
Params SchemaURL path values (e.g. the 42 in /users/42)

You only need to configure the ones that matter for your route — unused schemas are simply skipped.

Available Data Types ​

TypeWhat It Accepts
StringAny text, with optional rules like minimum length, maximum length, or a required format
IntegerA whole number, with optional min/max
FloatA decimal number, with optional min/max
Booleantrue or false
ArrayA list of items, with optional min/max item count
ObjectA structured set of named fields (can be nested)
EnumOne specific value from a predefined list
FileOne uploaded file from a multipart/form-data request, with optional size and file-type rules
BlobA raw binary body (application/octet-stream), with optional size rules
Use JavaScriptCustom validation logic you write yourself

A String field can also pick a ready-made Format. Any other value is rejected with a clear message, like Must be a valid UUID v4:

FormatAccepts
UUID v4 / UUID v7A UUID of that version, e.g. 550e8400-e29b-41d4-a716-446655440000
EmailAn email address
URLA URL with any protocol and a host, e.g. https://a.com, tcp://host:9000, rediss://host/0
IPv4 / IPv6 addressAn IP address of that version
ISO 8601 date-timee.g. 2024-01-01T10:00:00Z or 2024-01-01T10:00:00+05:30

TIP

Need something these don't cover, like only https URLs? Use a regex pattern or Use JavaScript.

Form Fields Are Converted for You ​

Everything in a form body (application/x-www-form-urlencoded or multipart/form-data) arrives as text, because that is how forms are sent. Fluxify converts form fields to the type your schema declares before checking them, the same way it does for query and path values:

Field typeSent in the formYour workflow receives
Integerage=2525
Booleanactive=falsefalse

A JSON body is not converted. JSON has real numbers and booleans, so { "age": "25" } fails an Integer field. Send { "age": 25 } instead.

Accepting Several Files ​

A File field takes exactly one file. To let callers upload more than one under the same name, make the field an Array and set its item type to File:

Field set up asOne file sentSeveral files sent
FileAcceptedRejected with 400
Array of FileAccepted, as a list of oneAccepted, as a list

Size and file-type rules on the item apply to each file. Minimum and maximum item counts on the array limit how many files can be sent.

Sending several files

In a multipart request, repeat the same field name once per file. With curl: curl -F [email protected] -F [email protected] ...

Marking Fields as Required ​

Each field in your schema can be marked as required or optional. Required fields must be present — if they're missing, the request is rejected with an error.

Custom JavaScript Validation ​

For rules that can't be expressed with the built-in types, you can switch a field to Use JavaScript and write your own logic. Your code receives the field's value and should either return true (validation passes) or throw a ValidationError with a custom message.

javascript
// Example: reject discount codes that don't start with "SALE"
if (!input.startsWith("SALE")) {
  throw new ValidationError({
    code: "INVALID_CODE",
    message: "Discount codes must start with SALE"
  });
}
return true;

Whatever you pass to ValidationError is returned directly to the caller — giving you full control over your error messages.

Validation schemas and their trusted JavaScript validators are compiled when a route artifact loads or hot-reloads. Requests only call the cached validator; they never compile schema definitions or request-provided js: strings. Values received from a caller are always treated as data, including strings beginning with js:.

Validation Error Response ​

When a request fails validation, the caller receives a 400 Bad Request with a JSON body that clearly describes what went wrong.

json
{
  "message": "Body validation failed",
  "errors": [
    {
      "path": "address.zipCode",
      "property": "zipCode",
      "errors": ["String must contain at least 5 character(s)"]
    },
    {
      "path": "age",
      "property": "age",
      "errors": ["Expected number, received string"]
    }
  ]
}
FieldDescription
messageWhich part of the request failed: body, query, or path parameters
errors[].pathThe full path to the failing field using dot notation (e.g. address.zipCode)
errors[].propertyJust the field name that failed (e.g. zipCode)
errors[].errorsOne or more error messages for that field

When a custom JavaScript validator throws a ValidationError, its payload appears verbatim in errors[].errors — exactly as you wrote it.

Error Responses at a Glance ​

Here's every possible outcome and what the caller receives:

SituationStatusResponse
Route doesn't exist404{ "message": "Route not found" }
Content type not accepted415{ "message": "Unsupported content type ..." }
Body too large413{ "message": "Request body exceeds the ...KB limit" }
Body couldn't be read400{ "message": "Malformed ... body: ..." }
Validation failed400{ "message": "...", "errors": [...] }
Workflow error500{ "error": "description" }
Unexpected crash500{ "message": "Internal server error" }
Success200Whatever your Response block returns

Custom Status Codes

Your workflow can return any HTTP status code you choose using the Response block — the defaults above only apply when no status is explicitly set.

Turning a Route On or Off ​

A route has an Enabled switch for each environment, in its settings under Advanced. A new route is on in Development and off in Production. Callers of your public URL get 404 until you turn Production on. A route that is off in an environment returns 404 there.

Trying a Route in the Playground ​

The Playground sends a real request to your route and shows the response. Open it with the Playground button on the Routes page, or the play button on the route's canvas.

A Run in Production toggle sits at the top. It opens on Development and does not remember your choice, so the next time you open the playground you are back on Development.

ToggleWhere the request goesWhat it runs with
Off (default, Development)The route's development address, /_/dev + the pathDevelopment worker, development values
On (Production)The route's public address, exactly as a caller uses itProduction's promoted version, production values

Development asks for nothing extra: the route must be on in Development, which a new route is, and Fluxify adds the development token for you. If no development worker is running, the playground says so and cannot send.

Production is offered only once you have promoted a version. Until then the toggle is disabled and says Not promoted yet. The first time you switch it on, the playground asks you to confirm: "This calls production: real data, real side effects." A production call really reaches your live route and can change real data.

When production recording is on for the route, a production call shows an Open recording link once the run is recorded, so you can open it on the Executions page. When recording is off, there is nothing to open and the link does not appear.

For POST and PUT routes, pick a content type on the Body tab. The editor changes to match it:

Content typeHow you fill in the body
application/json, text/plainType it into the editor
Form typesFill in the fields from your body schema. With no schema, add fields yourself; in multipart/form-data each field can hold text or a file
application/octet-streamChoose a file, or paste the data as base64

You can send a body even when the route has no body schema. Leave Validate on to have the playground check your input against the route's schemas before sending; turn it off to see how the route itself answers bad input.

Next Steps ​

Released under the Apache License 2.0. Enterprise features are under the Fluxify Enterprise Edition License.