Inject variable into macro function body

My termininology with the question title is probably all over the place, but I’m really struggling on how to phrase it.

What I essentially want to do, is something like plug does in its “get”/“post”, etc. macros: It injects the “conn” variable without having to declare it anywhere.

I have this macro:

defmacro socket(matcher, do: expr) do
  quote do
    def websocket_handle({:json, unquote(matcher) = json}, state) do
      try do
        unquote(expr)
      rescue
        e -> Logger.error("Websocket Error - #{inspect(e)}")
      end
    end
  end
end

and use it like this:

socket %{"action" => "join_chat", "id" => id} do
  my_fun(id)
  my_fun(json) # :(
  my_fun(state) # :(
  {:reply, %{}, state}
end

Now, the “id” variable declared in the matcher is readily available, however “json” and “state” are not. It’s certainly related to scope, but I have tried all sorts of different things - to no avail.

The “var!” macro didn’t really help because that required me to declare the variable first, which is the exact opposite of what I want. I looked at the plug source code, but I had a hard time following it.

Is what I want to do feasable with a small macro? If yes, how - if no, what are my alternatives for giving access to the “json” and “state” variables?

Thank you for your time!