defmodule Phantom.ResourcePlug do @moduledoc false @behaviour Plug import Plug.Conn alias Phantom.Request alias Phantom.Resource alias Phantom.Session @impl Plug def init(opts), do: opts @impl Plug def call(fake_conn, _opts) do session = %{ fake_conn.assigns.session | request: %{fake_conn.assigns.session.request | spec: fake_conn.assigns.resource_template} } handler = fake_conn.assigns.resource_template.handler function = fake_conn.assigns.resource_template.function args = if function_exported?(handler, function, 3) do [fake_conn.path_params, session, fake_conn] else [fake_conn.path_params, session] end result = try do apply(handler, function, args) rescue _e in FunctionClauseError -> {:error, Phantom.Request.resource_not_found(%{uri: fake_conn.assigns.uri}), fake_conn.assigns.session} end assign( fake_conn, :result, wrap(result, fake_conn.assigns.uri, fake_conn.assigns.session) ) end defp wrap({:error, reason}, _uri, session) do {:error, reason, session} end defp wrap({:error, _reason, %Session{}} = result, _uri, _session), do: result defp wrap(nil, uri, session) do {:error, Request.resource_not_found(%{uri: uri}), session} end defp wrap({:noreply, %Session{}} = result, _uri, _session), do: result defp wrap({:reply, nil, %Session{} = session}, uri, _session) do {:error, Request.resource_not_found(%{uri: uri}), session} end defp wrap({:reply, %{code: code, message: _} = error, %Session{} = session}, _uri, _session) when is_integer(code) and code < 0 do {:error, error, session} end defp wrap({:reply, results, %Session{} = session}, _uri, _session) do {:reply, Resource.response(results), session} end defmodule NotFound do @moduledoc false @behaviour Plug import Plug.Conn def init(opts), do: opts def call(conn, _opts) do result = Phantom.Request.resource_not_found(%{uri: conn.assigns.uri}) assign(conn, :result, {:error, result, conn.assigns.session}) end end end