Back to Blog

Your First Action: Defining and Executing a Business Operation

In the first three tutorials, we learned how to deploy coomia-dip, create Ontology models, and read/write data. In real enterprise applications however, data operations are rarely simple CRUD — they are composite operations with business rules. For example, "employee onboarding" involves creating an employee record, assigning a department, provisioning access, and sending notifications. Actions in coomia-dip are the core abstraction for encapsulating such business operations.

CoomiaPublished on January 13, 20266 min read
Share this articleTwitter / X

Series: S12 Developer Tutorials · Article 4 | Level: Beginner | Reading Time: 15 min

Your First Action: Defining and Executing a Business Operation

#Introduction

In the first three tutorials, we learned how to deploy coomia-dip, create Ontology models, and read/write data. In real enterprise applications however, data operations are rarely simple CRUD — they are composite operations with business rules. For example, "employee onboarding" involves creating an employee record, assigning a department, provisioning access, and sending notifications. Actions in coomia-dip are the core abstraction for encapsulating such business operations.

Action is coomia-dip's implementation of Palantir Foundry's Action Type. It lets you define business operations with parameters, validation rules, and side effects, callable uniformly through the SDK or API. Action execution is transactional — either all steps succeed or everything rolls back.

#Core Concepts

#What is an Action?

An Action is an executable business operation definition containing:

  • Name and description: Identifies what the operation does
  • Parameters: Required inputs for the operation
  • Validations: Business rule checks before execution
  • Operations: Actual data mutations to perform
  • Side Effects: Post-operation notifications, logging, etc.

#Action vs Direct CRUD

DimensionDirect CRUDAction
Business semanticsNoneClear business meaning
Parameter validationManualDeclarative rules
TransactionsManual managementAutomatic
Audit loggingManual recordingAutomatic
Access controlData-basedOperation-based
DiscoverabilityNoneAuto-exposed via API

#Creating Your First Action

#Scenario: Employee Onboarding

Python
from ontology_sdk import OntoPlatform

platform = OntoPlatform(
    control_plane_url="localhost:50051",
    data_plane_url="localhost:50052"
)

onboard_action = platform.actions.create(
    name="onboard_employee",
    display_name="Employee Onboarding",
    description="New employee onboarding: create record, assign department, set permissions",
    parameters={
        "name": {
            "type": "string",
            "required": True,
            "description": "Employee name"
        },
        "email": {
            "type": "string",
            "required": True,
            "description": "Work email",
            "constraints": {"format": "email"}
        },
        "department_id": {
            "type": "string",
            "required": True,
            "description": "Department ID"
        },
        "title": {
            "type": "string",
            "required": True,
            "description": "Job title"
        },
        "level": {
            "type": "integer",
            "required": True,
            "constraints": {"min": 1, "max": 15}
        },
        "salary": {
            "type": "decimal",
            "required": True,
            "description": "Monthly salary"
        },
        "hire_date": {
            "type": "date",
            "default": "today"
        }
    },
    validations=[
        {
            "name": "check_department_exists",
            "type": "object_exists",
            "object_type": "Department",
            "primary_key": {"ref": "parameters.department_id"},
            "error_message": "Department does not exist"
        },
        {
            "name": "check_email_unique",
            "type": "unique_check",
            "object_type": "Employee",
            "property": "email",
            "value": {"ref": "parameters.email"},
            "error_message": "Email already in use"
        }
    ],
    operations=[
        {
            "type": "create_object",
            "object_type": "Employee",
            "properties": {
                "employee_id": {"ref": "generated.employee_id"},
                "name": {"ref": "parameters.name"},
                "email": {"ref": "parameters.email"},
                "title": {"ref": "parameters.title"},
                "level": {"ref": "parameters.level"},
                "salary": {"ref": "parameters.salary"},
                "hire_date": {"ref": "parameters.hire_date"},
                "is_active": True
            },
            "output_ref": "new_employee"
        },
        {
            "type": "create_relation",
            "relation_type": "belongs_to",
            "source": {"ref": "new_employee.rid"},
            "target": {"ref": "parameters.department_id"},
            "properties": {
                "joined_at": {"ref": "parameters.hire_date"},
                "role_in_dept": "member"
            }
        }
    ],
    side_effects=[
        {
            "type": "send_notification",
            "channel": "email",
            "template": "welcome_employee",
            "to": {"ref": "parameters.email"}
        },
        {
            "type": "audit_log",
            "event": "employee_onboarded"
        }
    ]
)

#Executing Actions

Python
result = platform.actions.execute(
    action_name="onboard_employee",
    parameters={
        "name": "Alice Chen",
        "email": "alice.new@example.com",
        "department_id": "DEPT-001",
        "title": "Junior Engineer",
        "level": 3,
        "salary": 80000.00
    }
)

print(f"Status: {result.status}")
print(f"Employee RID: {result.outputs['new_employee']['rid']}")

# Handling validation errors
if result.status == "VALIDATION_ERROR":
    for error in result.validation_errors:
        print(f"Validation failed: {error.validation_name} - {error.message}")

#More Action Examples

#Employee Transfer

Python
transfer_action = platform.actions.create(
    name="transfer_employee",
    display_name="Employee Transfer",
    description="Transfer employee from one department to another",
    parameters={
        "employee_id": {"type": "string", "required": True},
        "new_department_id": {"type": "string", "required": True},
        "new_title": {"type": "string"},
        "effective_date": {"type": "date", "default": "today"}
    },
    validations=[
        {
            "name": "check_employee_active",
            "type": "property_check",
            "object_type": "Employee",
            "primary_key": {"ref": "parameters.employee_id"},
            "property": "is_active",
            "expected": True,
            "error_message": "Employee is inactive"
        }
    ],
    operations=[
        {
            "type": "delete_relation",
            "relation_type": "belongs_to",
            "source_filter": {"employee_id": {"ref": "parameters.employee_id"}}
        },
        {
            "type": "create_relation",
            "relation_type": "belongs_to",
            "source": {"ref": "parameters.employee_id"},
            "target": {"ref": "parameters.new_department_id"},
            "properties": {"joined_at": {"ref": "parameters.effective_date"}}
        }
    ]
)

#Project Status Change

Python
change_status = platform.actions.create(
    name="change_project_status",
    display_name="Change Project Status",
    parameters={
        "project_id": {"type": "string", "required": True},
        "new_status": {
            "type": "enum",
            "values": ["planning", "in_progress", "on_hold", "completed", "cancelled"],
            "required": True
        },
        "reason": {"type": "string"}
    },
    operations=[
        {
            "type": "update_object",
            "object_type": "Project",
            "primary_key": {"ref": "parameters.project_id"},
            "properties": {"status": {"ref": "parameters.new_status"}}
        }
    ]
)

#Action Permissions

Python
platform.actions.set_permissions(
    action_name="onboard_employee",
    permissions={
        "allowed_roles": ["hr_manager", "admin"],
        "require_approval": False
    }
)

platform.actions.set_permissions(
    action_name="transfer_employee",
    permissions={
        "allowed_roles": ["hr_manager", "department_head"],
        "require_approval": True,
        "approval_chain": ["department_head", "hr_director"]
    }
)

#YAML Action Definition

YAML
# actions/onboard_employee.yaml
name: onboard_employee
display_name: Employee Onboarding
description: New employee onboarding process

parameters:
  - name: name
    type: string
    required: true
  - name: email
    type: string
    required: true
    constraints:
      format: email
  - name: department_id
    type: string
    required: true
  - name: title
    type: string
    required: true
  - name: level
    type: integer
    required: true
    constraints: {min: 1, max: 15}
  - name: salary
    type: decimal
    required: true

validations:
  - name: check_department_exists
    type: object_exists
    object_type: Department
    primary_key: $parameters.department_id
  - name: check_email_unique
    type: unique_check
    object_type: Employee
    property: email
    value: $parameters.email

operations:
  - type: create_object
    object_type: Employee
    properties:
      employee_id: $generated.employee_id
      name: $parameters.name
      email: $parameters.email
      title: $parameters.title
      level: $parameters.level
      salary: $parameters.salary
      is_active: true
    output_ref: new_employee
  - type: create_relation
    relation_type: belongs_to
    source: $new_employee.rid
    target: $parameters.department_id

permissions:
  allowed_roles: [hr_manager, admin]

#Execution History and Audit

Python
history = platform.actions.get_execution_history(
    action_name="onboard_employee",
    limit=20
)

for record in history:
    print(f"  {record.execution_id}: {record.status} at {record.timestamp} by {record.user}")

#Comparison with Palantir Foundry

FeaturePalantir Foundrycoomia-dip
Action DefinitionWeb UI / TypeScriptSDK + YAML + API
Parameter ValidationBuilt-inDeclarative + Custom Functions
Transaction SupportYesYes
Approval WorkflowWorkshopBuilt-in Approval Chain
Audit LoggingAutomaticAutomatic
Access ControlRBACRBAC + ABAC

#Best Practices

  1. Atomic Design: Each Action should represent one complete business operation
  2. Thorough Validation: Validate all business rules before operations
  3. Clear Parameters: Every parameter needs type, description, and constraints
  4. Separate Side Effects: Notifications and logging should not affect core operations
  5. Least Privilege: Grant only necessary execution permissions
  6. Version Control: Keep YAML Action definitions in version control

#Summary

In this tutorial, we learned about coomia-dip's Action mechanism: defining business operations with parameters, validations, operations, and side effects. Actions bridge data models and business processes, encapsulating complex logic into reusable, auditable, and controllable operation units.

This is Article 4 in the coomia-dip Developer Tutorial series. Repository: https://github.com/coomia-dip/coomia-dip | License: Apache License 2.0