Hello,
In my Phoenix controller, I have a case
statement whose argument is a call to a service layer module. I’m trying to implement a standardized ServiceError struct for all service layer modules, and pattern match on the struct in case of a failure:
case PostService.read(id, :id) do
{:ok, post} ->
render(conn, "show.html", post: post)
%ServiceError{cause: ErrorDefs.not_found} ->
Helpers.render_not_found(conn)
end
Notice “ErrorDefs.not_found
”. Initially I was simply passing atoms around, but that seemed hard to maintain in the long run. I want to use something that can be documented in a way that IDE tooling can work with. So basically, I have a module named ErrorDefs
(which is require
'd at the top of the controller), and ErrorDefs
defines macros with arity of 0 and a simple atom as an output:
defmodule Project.ErrorDefs do
defmacro not_found(), do: :not_found
end
Now, I get the following compilation error:
cannot invoke remote function ErrorDefs.not_found/0 inside match
which is strange for a few reasons. First, it’s a macro and not a function. Second, I wrote a small project just to test this out, and it worked fine in there (I’ll include below). previously I tried writing everything in ErrorDefs
as inlined functions, but I got the same error and decided that macros would be more appropriate.
Is there something unusual about Phoenix controllers that would keep macros from expanding in this scenario?
Any help is appreciated!
Test file:
defmodule Macros do
defmacro singleton(), do: :hello
defstruct [:key]
end
defmodule Example do
require Macros
def test do
case %Macros{key: Macros.singleton} do
# Compiles fine, running `Examples.test` returns `:ok`
%Macros{key: Macros.singleton} ->
:ok
_ ->
:error
end
end
end