Skip to content

Instantly share code, notes, and snippets.

@ChristianAlexander
Last active February 7, 2026 20:53
Show Gist options
  • Select an option

  • Save ChristianAlexander/27582ecb257954c2c8bddc272b5f5071 to your computer and use it in GitHub Desktop.

Select an option

Save ChristianAlexander/27582ecb257954c2c8bddc272b5f5071 to your computer and use it in GitHub Desktop.
Passing metadata as ash_json_api response headers
defmodule KitchenManager.Changes.DBTransactionId do
use Ash.Resource.Change
@impl true
def atomic?(), do: true
@impl true
def change(changeset, _opts, _context) do
Ash.Changeset.after_action(changeset, fn _changeset, record ->
record =
case Phoenix.Sync.Writer.txid(KitchenManager.Repo) do
{:ok, id} ->
Ash.Resource.put_metadata(record, :txid, id)
_ ->
record
end
{:ok, record}
end)
end
def get_value(record) do
Ash.Resource.get_metadata(record, :txid)
end
def put_txid_header(conn, _subject, result, _request) do
txid = KitchenManager.Changes.DBTransactionId.get_value(result)
if txid do
Plug.Conn.put_resp_header(conn, "x-txid", to_string(txid))
else
conn
end
end
end
defmodule KitchenManager.Orders.Order do
use Ash.Resource,
domain: KitchenManager.Orders,
data_layer: AshPostgres.DataLayer,
extensions: [AshJsonApi.Resource]
json_api do
type "order"
includes [
items: :menu_item
]
end
postgres do
table "orders"
repo KitchenManager.Repo
end
actions do
defaults [:read]
create :create do
accept [:customer_name]
argument :items, {:array, :map} do
allow_nil? false
constraints min_length: 1
end
change manage_relationship(:items, :items, type: :create)
change KitchenManager.Changes.DBTransactionId
end
update :update do
accept [:state, :customer_name]
change KitchenManager.Changes.DBTransactionId
end
destroy :destroy do
change KitchenManager.Changes.DBTransactionId
end
end
attributes do
integer_primary_key :id
attribute :customer_name, :string do
allow_nil? false
public? true
end
attribute :state, :atom do
public? true
allow_nil? false
default :new
constraints one_of: [:new, :preparing, :completed]
end
create_timestamp :inserted_at do
public? true
end
update_timestamp :updated_at do
public? true
end
end
relationships do
has_many :items, KitchenManager.Orders.Item do
public? true
end
end
end
defmodule KitchenManager.Orders do
use Ash.Domain, extensions: [AshJsonApi.Domain]
json_api do
routes do
base_route "/orders", KitchenManager.Orders.Order do
get :read
index :read
patch :update do
modify_conn(&KitchenManager.Changes.DBTransactionId.put_txid_header/4)
end
post :create do
modify_conn(&KitchenManager.Changes.DBTransactionId.put_txid_header/4)
end
delete :destroy do
modify_conn(&KitchenManager.Changes.DBTransactionId.put_txid_header/4)
end
end
base_route "/order-items", KitchenManager.Orders.Item do
patch :update do
modify_conn(&KitchenManager.Changes.DBTransactionId.put_txid_header/4)
end
delete :destroy do
modify_conn(&KitchenManager.Changes.DBTransactionId.put_txid_header/4)
end
end
end
end
resources do
resource KitchenManager.Orders.Order do
define :create_order, action: :create
define :list_orders, action: :read
define :get_order, get_by: :id, action: :read, not_found_error?: false
define :update_order, action: :update
end
resource KitchenManager.Orders.Item
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment