Jido.Signal.Ext behaviour (Jido Signal v1.2.0)

View Source

Defines the core extension behavior and using macro for Signal extensions.

Extensions allow Signal to be enhanced with domain-specific functionality while maintaining compatibility with the core CloudEvents specification. Each extension provides a namespace, schema validation, and serialization support.

Overview

Extensions are modules that implement the Jido.Signal.Ext behavior and use the provided __using__ macro. They automatically register themselves at compile time and provide consistent interfaces for attribute conversion.

Creating Extensions

Use the __using__ macro to create a new extension:

defmodule MyApp.Signal.Ext.Auth do
  use Jido.Signal.Ext,
    namespace: "auth",
    schema: [
      user_id: [type: :string, required: true],
      roles: [type: {:list, :string}, default: []],
      expires_at: [type: :pos_integer]
    ]
end

Extension Registration

Extensions are automatically registered at compile time via an @after_compile hook. This enables runtime lookup and validation without requiring manual registration steps.

Namespace Rules

  • Must be lowercase strings
  • Should use dots for hierarchical namespaces (e.g., "auth.oauth")
  • Cannot conflict with CloudEvents standard fields
  • Should be unique across your application

Schema Validation

Extensions use NimbleOptions for schema validation:

  • :type - Data type validation
  • :required - Required fields
  • :default - Default values
  • Custom validators supported

Usage with Signals

Extensions integrate seamlessly with Signal creation:

{:ok, signal} = Jido.Signal.new("user.login", %{username: "bob"}, 
  auth: %{user_id: "123", roles: ["user", "admin"]}
)

# Extension data is validated and accessible
assert signal.auth.user_id == "123"
assert signal.auth.roles == ["user", "admin"]

See Also

Summary

Callbacks

Converts Signal attributes back to extension data format.

Returns the namespace for this extension.

Returns the NimbleOptions schema for validating extension data.

Converts extension data to Signal attributes format.

Functions

Defines a Signal extension module.

Callbacks

from_attrs(term)

@callback from_attrs(term()) :: term()

Converts Signal attributes back to extension data format.

Takes data from Signal attributes and converts it back to the extension's expected format. The default implementation returns the data unchanged.

Parameters

  • attrs - Data from Signal attributes

Returns

The data in extension format

namespace()

@callback namespace() :: String.t()

Returns the namespace for this extension.

The namespace determines the field name used when attaching extension data to Signals.

schema()

@callback schema() :: keyword()

Returns the NimbleOptions schema for validating extension data.

The schema defines the structure, types, and validation rules for data within this extension's namespace.

to_attrs(term)

@callback to_attrs(term()) :: term()

Converts extension data to Signal attributes format.

Takes validated extension data and converts it to the format used in Signal attribute maps. The default implementation returns the data unchanged.

Parameters

  • data - Validated extension data

Returns

The data in Signal attribute format

Functions

__using__(opts)

(macro)

Defines a Signal extension module.

This macro sets up the necessary callbacks and registrations for a Signal extension, including schema validation and automatic registry integration.

Options

  • :namespace - String namespace for the extension (required)
  • :schema - NimbleOptions schema for validation (default: [])

Examples

defmodule MyApp.Signal.Ext.Tracking do
  use Jido.Signal.Ext,
    namespace: "tracking",
    schema: [
      session_id: [type: :string, required: true],
      user_agent: [type: :string],
      ip_address: [type: :string]
    ]
end

The extension will be automatically registered and available for use:

# Look up the extension
{:ok, ext} = Jido.Signal.Ext.Registry.get("tracking")

# Use in Signal creation
{:ok, signal} = Jido.Signal.new("page.view", %{url: "/home"},
  tracking: %{session_id: "abc123", user_agent: "Mozilla/5.0"}
)