Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/ash_json_api/serializer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1258,11 +1258,23 @@ defmodule AshJsonApi.Serializer do
req = %{fields: %{}, route: %{}, domain: domain}
serialize_attributes(req, value, opts)
else
value
dump_struct_value(value, type, constraints)
end
end
end

# A struct whose type is a non-resource Ash type (e.g. a TypedStruct or an
# embedded type) isn't JSON-encodable as-is. Dump it through the type into a
# native map; non-struct values pass through unchanged.
defp dump_struct_value(value, type, constraints) when is_struct(value) do
case Ash.Type.dump_to_embedded(type, value, constraints || []) do
{:ok, dumped} -> dumped
_ -> value
end
end

defp dump_struct_value(value, _type, _constraints), do: value

defp flatten_new_type(type, constraints) do
if Ash.Type.NewType.new_type?(type) do
new_constraints = Ash.Type.NewType.constraints(type, constraints)
Expand Down
26 changes: 26 additions & 0 deletions test/acceptance/route_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
defmodule Test.Acceptance.RouteTest do
use ExUnit.Case, async: true

defmodule Greeting do
use Ash.TypedStruct

typed_struct do
field(:message, :string, allow_nil?: false)
field(:count, :integer)
end
end

defmodule Actions do
use Ash.Resource,
domain: Test.Acceptance.RouteTest.Domain,
Expand All @@ -16,6 +25,7 @@ defmodule Test.Acceptance.RouteTest do
route(:get, "/say_hello", :say_hello, query_params: [:to])
route(:post, "/required_say_hello/:to", :with_required)
route(:post, "/trigger_job", :trigger_job)
route(:get, "/say_hello_struct/:to", :say_hello_struct)
end
end

Expand All @@ -42,6 +52,15 @@ defmodule Test.Acceptance.RouteTest do
:ok
end)
end

action :say_hello_struct, Test.Acceptance.RouteTest.Greeting do
argument(:to, :string, allow_nil?: false)

run(fn input, _ ->
{:ok,
%Test.Acceptance.RouteTest.Greeting{message: "Hello, #{input.arguments.to}!", count: 1}}
end)
end
end
end

Expand Down Expand Up @@ -94,6 +113,13 @@ defmodule Test.Acceptance.RouteTest do
|> Kernel.==(%{"success" => true})
end

test "generic actions returning a TypedStruct are serialized without a Jason encoder" do
assert Domain
|> get("/say_hello_struct/fred", status: 200)
|> Map.get(:resp_body)
|> Kernel.==(%{"message" => "Hello, fred!", "count" => 1})
end

test "generic actions with required inputs" do
assert Domain
|> post(
Expand Down
Loading