I am trying to use the Phoenix Framework’s PubSub module in a number of GenServers, however I would like to have a well-defined list of topics to reference instead of raw strings.
Currently my code looks something like this:
# ...
def init(_args) do
Phoenix.PubSub.subscribe(:my_pubsub, "topic_name")
end
# ...
def handle_info({"topic_name", data = %SomeData{}}, state) do
# do stuff with data ...
end
# in a different module:
Phoenix.PubSub.broadcast(:my_pubsub, "topic_name", %SomeData{key: value})
This works, but the use of a raw string for the topic name is deficient for several reasons: it requires me to check everywhere that “topic_name” is used to verify that it is spelled correctly, if there is an existing topic name, I need to look through the code to find it, if I misspell it I get no warning, and if I want to examine a list of all possible topics, I have to look through the code and find all the unique topics given in the subscribe or broadcast calls — this also means I can’t give them sensible documentation.
As far as I’m concerned, using atoms for the topic names would have the same problems, but PubSub only allows topics to be strings.
What I’d like is a way to define all topics in one module and reference them AND pattern match on them, like so:
def handle_info({Topics.some_topic, data = %SomeData{}}, state) do
# do stuff...
end
In every other language I’ve ever used, this sort of pattern is straightforward. However, Elixir does not offer any way of sharing constants between modules (at least not any that I could find). Is there any way I can achieve what I’m looking for or do I need to get used to having things the way I described at the beginning?