Forja.Event.Schema (Forja v0.4.0)

View Source

Macro module that provides a DSL for defining typed, validated event schemas using Zoi.

Use this module in event definition modules to get compile-time validated payload schemas with automatic parsing and upcasting support.

Example

defmodule MyApp.Events.OrderCreated do
  use Forja.Event.Schema,
    event_type: "order:created",
    schema_version: 2,
    queue: :payments,
    forja: :my_app,
    source: "checkout"

  payload do
    field :user_id, Zoi.string()
    field :amount_cents, Zoi.integer() |> Zoi.positive()
    field :currency, Zoi.string() |> Zoi.default("USD"), required: false
  end

  def upcast(1, payload) do
    %{"user_id" => payload["customer_id"], "amount_cents" => payload["total"]}
  end

  def idempotency_key(payload) do
    "order_created:#{payload["user_id"]}"
  end
end

When :forja is provided, the module also generates emit/1,2 and emit_multi/2,3 convenience functions:

# Instead of Forja.emit(:my_app, MyApp.Events.OrderCreated, payload: ..., source: ...)
MyApp.Events.OrderCreated.emit(%{user_id: "u123", amount_cents: 500})

# With overrides
MyApp.Events.OrderCreated.emit(%{user_id: "u123", amount_cents: 500},
  source: "manual_payment"
)

# In an Ecto.Multi
Ecto.Multi.new()
|> Ecto.Multi.insert(:order, changeset)
|> MyApp.Events.OrderCreated.emit_multi(
  payload_fn: fn %{order: o} -> %{user_id: o.user_id, amount_cents: o.total} end
)
|> Forja.transaction(:my_app)

Options

  • :event_type - String identifier for this event type (required)
  • :schema_version - Positive integer for payload versioning (default: 1)
  • :queue - Atom for Oban queue routing, prefixed with forja_ internally (default: nil)
  • :forja - Atom for the Forja instance name; enables emit/1,2 and emit_multi/2,3 (default: nil)
  • :source - Default source string for events emitted via emit/1,2 (default: nil)

Generated functions

  • __forja_event_schema__/0 - Returns true, marker for runtime detection
  • event_type/0 - Returns the configured event type string
  • schema_version/0 - Returns the schema version (default: 1)
  • queue/0 - Returns the configured queue name or nil
  • parse_payload/1 - Validates input against the Zoi schema
  • upcast/2 - Upcasts an old payload version to the current version (overridable)
  • idempotency_key/1 - Returns an idempotency key from payload (overridable, default: nil)

When :forja is provided, also generates:

Compile-time validations

Summary

Functions

Defines a payload field with a Zoi type and optional configuration.

Defines a scoped payload block where fields are declared.

Functions

field(name, zoi_type, opts \\ [])

(macro)

Defines a payload field with a Zoi type and optional configuration.

Arguments

  • name - The field name (atom)
  • zoi_type - A Zoi type expression (e.g., Zoi.string(), Zoi.integer() |> Zoi.positive())
  • opts - Optional keyword list. Fields are required by default. Use required: false to make a field optional.

Example

field :user_id, Zoi.string()
field :amount, Zoi.integer() |> Zoi.positive()
field :currency, Zoi.string() |> Zoi.default("USD"), required: false

payload(list)

(macro)

Defines a scoped payload block where fields are declared.

Inside the block, use field/3 to define each payload field.

Example

payload do
  field :user_id, Zoi.string(), required: true
  field :amount, Zoi.integer()
end