defmodule Jido.Chat.WebhookResponse do
@moduledoc """
Typed webhook response envelope.
"""
alias Jido.Chat.Wire
@schema Zoi.struct(
__MODULE__,
%{
status: Zoi.integer() |> Zoi.default(200),
headers: Zoi.map() |> Zoi.default(%{}),
body: Zoi.any() |> Zoi.nullish(),
metadata: Zoi.map() |> Zoi.default(%{})
},
coerce: true
)
@type t :: unquote(Zoi.type_spec(@schema))
@enforce_keys Zoi.Struct.enforce_keys(@schema)
defstruct Zoi.Struct.struct_fields(@schema)
@doc "Returns the Zoi schema for WebhookResponse."
def schema, do: @schema
@doc "Creates a typed webhook response envelope."
@spec new(map()) :: t()
def new(attrs) when is_map(attrs), do: Jido.Chat.Schema.parse!(__MODULE__, @schema, attrs)
@doc "Returns a default accepted response."
@spec accepted(map() | nil) :: t()
def accepted(body \\ nil), do: new(%{status: 200, body: body || %{ok: true}})
@doc "Returns an error response envelope."
@spec error(integer(), map() | String.t() | nil) :: t()
def error(status, body \\ nil) when is_integer(status) do
body =
cond do
is_map(body) -> body
is_binary(body) -> %{error: body}
true -> %{error: "request_failed"}
end
new(%{status: status, body: body})
end
@doc "Serializes webhook response into plain map with type marker."
@spec to_map(t()) :: map()
def to_map(%__MODULE__{} = response) do
response
|> Map.from_struct()
|> Wire.to_plain()
|> Map.put("__type__", "webhook_response")
end
@doc "Builds webhook response from serialized data."
@spec from_map(map()) :: t()
def from_map(map) when is_map(map), do: new(map)
end