Files
attune/work-summary/sessions/2025-01-27-api-ref-only-access.md
2026-02-04 17:46:30 -06:00

7.6 KiB

API Endpoint Changes: Ref-Only Access for Deployable Components

Date: 2025-01-27
Status: Complete
Impact: Breaking change for API consumers using ID-based endpoints

Overview

Updated all API endpoints to use reference identifiers (ref) exclusively for accessing deployable components. Removed redundant ID-based alternative endpoints (/id/{id}) to enforce consistency and align with the architectural principle that deployable components should be accessed by portable reference strings, not database IDs.

Motivation

  • Consistency: Single, clear way to access deployable components
  • Portability: Refs are portable across environments (dev, staging, prod)
  • Semantics: Reference strings (e.g., core.http.get) are more meaningful than numeric IDs
  • Architectural alignment: Enforces design principle that IDs are only for transient data (executions, events, enforcements)

Changes Made

1. Code Changes (Phase 1)

Removed ID-based endpoints and their handler functions from:

Files Modified:

  • crates/api/src/routes/actions.rs

    • Removed: get_action_by_id() function
    • Removed: .route("/actions/id/{id}", get(get_action_by_id))
    • Removed: Unused FindById import
  • crates/api/src/routes/triggers.rs

    • Removed: get_trigger_by_id() function
    • Removed: get_sensor_by_id() function
    • Removed: .route("/triggers/id/{id}", get(get_trigger_by_id))
    • Removed: .route("/sensors/id/{id}", get(get_sensor_by_id))
    • Removed: Unused FindById import
  • crates/api/src/routes/rules.rs

    • Removed: get_rule_by_id() function
    • Removed: .route("/rules/id/{id}", get(get_rule_by_id))
    • Removed: Unused FindById import
  • crates/api/src/routes/workflows.rs

    • Removed: get_workflow_by_id() function
    • Removed: .route("/workflows/id/{id}", get(get_workflow_by_id))
    • Removed: Unused FindById import
  • crates/api/src/routes/packs.rs

    • Removed: get_pack_by_id() function
    • Removed: .route("/packs/id/{id}", get(get_pack_by_id))
  • crates/api/src/openapi.rs

    • Removed: OpenAPI path references for all deleted *_by_id endpoints
    • Updated: Test assertions for expected path/operation counts (62→57 paths, 86→81 operations)

Total Removals:

  • 6 handler functions (~180 lines)
  • 6 route registrations
  • 6 OpenAPI path annotations
  • 5 unused imports

2. Documentation Updates (Phase 2)

Files Updated:

  • docs/api-actions.md

    • Removed: "Get Action by ID" section (35 lines)
  • docs/api-triggers-sensors.md

    • Removed: "Get Trigger by ID" section (16 lines)
    • Removed: "Get Sensor by ID" section (16 lines)
  • docs/api-rules.md

    • Removed: "Get Rule by ID" section (16 lines)
  • docs/api-packs.md

    • Removed: "Get Pack by ID" section (21 lines)
    • Fixed: Section numbering (3→8 renumbered to 2→7)

Total Documentation:

  • ~104 lines removed
  • Section numbering corrected in pack documentation

3. Verification (Phase 3)

Tests:

  • All unit tests pass (cargo test -p attune-api --lib)
  • No test files reference deleted endpoints
  • OpenAPI spec tests updated and passing
  • Full project builds without errors

API Impact Analysis:

  • No E2E test scripts use ID-based endpoints
  • No web UI code references ID-based endpoints
  • No shell scripts reference deleted endpoints

API Changes

Removed Endpoints

Old Endpoint Replacement
GET /api/v1/actions/id/{id} GET /api/v1/actions/{ref}
GET /api/v1/triggers/id/{id} GET /api/v1/triggers/{ref}
GET /api/v1/sensors/id/{id} GET /api/v1/sensors/{ref}
GET /api/v1/rules/id/{id} GET /api/v1/rules/{ref}
GET /api/v1/workflows/id/{id} GET /api/v1/workflows/{ref}
GET /api/v1/packs/id/{id} GET /api/v1/packs/{ref}

Unchanged Endpoints (Correct from the start)

These endpoints already correctly use ref as the primary identifier:

Actions:

  • GET /api/v1/actions/{ref}
  • PUT /api/v1/actions/{ref}
  • DELETE /api/v1/actions/{ref}
  • GET /api/v1/packs/{pack_ref}/actions

Triggers:

  • GET /api/v1/triggers/{ref}
  • PUT /api/v1/triggers/{ref}
  • DELETE /api/v1/triggers/{ref}
  • POST /api/v1/triggers/{ref}/enable
  • POST /api/v1/triggers/{ref}/disable
  • GET /api/v1/packs/{pack_ref}/triggers

Sensors:

  • GET /api/v1/sensors/{ref}
  • PUT /api/v1/sensors/{ref}
  • DELETE /api/v1/sensors/{ref}
  • POST /api/v1/sensors/{ref}/enable
  • POST /api/v1/sensors/{ref}/disable
  • GET /api/v1/packs/{pack_ref}/sensors
  • GET /api/v1/triggers/{trigger_ref}/sensors

Rules:

  • GET /api/v1/rules/{ref}
  • PUT /api/v1/rules/{ref}
  • DELETE /api/v1/rules/{ref}
  • POST /api/v1/rules/{ref}/enable
  • POST /api/v1/rules/{ref}/disable
  • GET /api/v1/packs/{pack_ref}/rules
  • GET /api/v1/actions/{action_ref}/rules
  • GET /api/v1/triggers/{trigger_ref}/rules

Workflows:

  • GET /api/v1/workflows/{ref}
  • PUT /api/v1/workflows/{ref}
  • DELETE /api/v1/workflows/{ref}
  • GET /api/v1/packs/{pack_ref}/workflows

Packs:

  • GET /api/v1/packs/{ref}
  • PUT /api/v1/packs/{ref}
  • DELETE /api/v1/packs/{ref}
  • POST /api/v1/packs/{ref}/test
  • GET /api/v1/packs/{ref}/tests
  • POST /api/v1/packs/{ref}/workflows/sync
  • POST /api/v1/packs/{ref}/workflows/validate

Transient Resources (Correctly use ID):

  • GET /api/v1/executions/{id}
  • GET /api/v1/events/{id}
  • GET /api/v1/enforcements/{id}
  • GET /api/v1/inquiries/{id}

Migration Guide

For API Consumers

If you were using ID-based endpoints, update your code:

Before:

# ❌ No longer works
GET /api/v1/actions/id/123
GET /api/v1/triggers/id/456

After:

# ✅ Use ref instead
GET /api/v1/actions/core.http.get
GET /api/v1/triggers/webhooks.github_push

How to migrate:

  1. If you have an ID, first fetch the list and find the ref
  2. Update your code to store and use refs instead of IDs
  3. Use refs in all API calls for deployable components

For Pack Developers

No changes needed! Pack manifests already use refs:

# pack.yaml - already correct
actions:
  - ref: mypack.my_action  # ✅ ref-based
rules:
  - ref: mypack.my_rule    # ✅ ref-based
    action_ref: mypack.my_action  # ✅ ref-based
    trigger_ref: core.timer       # ✅ ref-based

Benefits

  1. Simplified API: One way to access each resource type
  2. Better DX: Refs are human-readable (e.g., core.http.get vs 123)
  3. Cross-environment: Refs work across dev/staging/prod without changes
  4. Enforced architecture: Clear distinction between deployable and transient resources
  5. Reduced code: 180+ lines of redundant code removed

Breaking Changes

⚠️ This is a breaking change for any consumers using the /id/{id} endpoints for:

  • Actions
  • Triggers
  • Sensors
  • Rules
  • Workflows
  • Packs

Mitigation: Since the project has no current users (early development), no migration path is needed.

Testing

All automated tests continue to pass:

  • Unit tests: 57 passed
  • Route structure tests: All passing
  • OpenAPI spec generation: Valid
  • Full project build: Successful

Next Steps

None required. The change is complete and verified.