Action Types
Action Types are reusable TypeScript functions that define custom business logic for automations. They encapsulate complex operations into modular, testable units that can be used across multiple workflows.
What are Action Types?
Action Types are TypeScript classes that:
- Execute custom logic - Perform complex operations beyond simple CRUD
- Access all Stack9 services - Database, entity service, query library, workflows
- Accept parameters - Define typed inputs with validation rules
- Return structured responses - Pass data to subsequent actions or return to caller
- Handle errors gracefully - Built-in error handling and logging
When you define an action type, Stack9 automatically:
- ✅ Validates input parameters
- ✅ Provides access to services and context
- ✅ Manages error handling and logging
- ✅ Supports async operations
- ✅ Enables workflow chaining
Why Use Action Types?
Without Action Types (Inline Logic)
// Logic scattered across multiple automations
// Hard to test, hard to reuse, hard to maintain
app.post('/api/sync-customer', async (req, res) => {
const { customerId } = req.body;
// Fetch customer
const customer = await db('customers').where({ id: customerId }).first();
// Update search index
await opensearch.index({
index: 'customers',
id: customer.id,
body: customer,
});
// Send to queue
await queue.send('customer-synced', customer);
res.json({ success: true });
});
With Action Types (Stack9 Approach)
export class SyncCustomerData implements S9AutomationActionType {
description = {
name: 'Sync customer data',
key: 'sync_customer_data',
properties: [
{
name: 'customerId',
label: 'Customer ID',
type: S9InputTypes.ValueCodeMirror,
rules: [{ required: true }],
},
],
};
execute = async ({ params, services, next }: S9AutomationContext) => {
const { customerId } = Params.check(params);
await services.search.syncCustomer(customerId);
next();
};
}
Benefits:
- ✅ Reusable: Use same action across multiple automations
- ✅ Testable: Easy to unit test in isolation
- ✅ Type-safe: Full TypeScript type checking
- ✅ Discoverable: Shows up in automation builder
- ✅ Maintainable: Change once, update everywhere
Action Type File Structure
Action types are defined in src/action-types/{action_name}.ts:
import {
S9AutomationActionType,
S9AutomationActionTypeDescription,
S9AutomationContext,
S9InputTypes,
} from '@april9au/stack9-sdk';
import * as rt from 'runtypes';
const Params = rt.Record({
// Define parameters with types
customerId: rt.Number,
});
type Params = rt.Static<typeof Params>;
export class ActionTypeName implements S9AutomationActionType {
description: S9AutomationActionTypeDescription = {
name: 'Human Readable Name',
key: 'action_type_key',
description: 'What this action does',
icon: 'EmailIcon',
properties: [
// Define input parameters
],
};
execute = async (context: S9AutomationContext): Promise<void> => {
// Your business logic here
const { params, services, next } = context;
const validatedParams = Params.check(params);
// Do work...
next(); // Continue to next action
};
}