Crowdhailer

Crowdhailer

Creator of Raxx

Sinatra-inspired web routing DSL, includes streaming. Interested in feedback

I have started experimenting with a web routing Domain Specific Language(DSL).

The DSL is inspired from working with several minimal web frameworks including Sinatra, roda etc. The heritage is not overly important as the question is about macro best practice. I wanted a simple DSL but my particular requirement was to match on url before method.

My first attempt looked like the following.

route "/user/:id" do
  :GET ->
    IO.inspect(id) # This implicit variable matches the identifier from the URL
    IO.inspect(request) # This implicit variable is always added to the context
    IO.inspect(config) # Same as request
    # actual work here to return request
  :POST ->
    # Other methods etc
end

However to create this DSL I have needed to use Macro.var, and this can mess with the hygiene of a macro. To see what would be required to not implicitly set variables I got to the following DSL.

route "/users/:id", [user_id] do
  get(request, config) ->
    IO.inspect(user_id) # explicitly named in route macro
    IO.inspect(request) # explicitly named in get macro
    IO.inspect(config) # Same as request
    # actual work here to return request
  post(r) ->
    IO.inspect(r) # Named r for brevity
    # config not used so not matched on
end

I see the trade off between the two as follows, version one is slightly more succinct but at the cost of being more “magic”. In addition this magic messing with the hygiene of the macro may have further side effects that I don’t know about yet.

Because of this I am leaning towards favoring the second more explicit DSL but would be interested in other opinions.


Update:

I have abandoned efforts to write a Sinatra style routing DSL. As any useful API must be documented I have decided to use that documentation as a router. My implementation of this is Raxx.Blueprint that will parse an API Blueprint file and generate forward requests to controllers based on that.

Most Liked

Crowdhailer

Crowdhailer

Creator of Raxx

Here is what an example chat server currently looks like, with this DSL

defmodule Example do
  use Tokumei

  config :port, 8080
  config :static, "./public"
  config :templates, "./templates"

  route "/" do
    get() ->
      ok(home_page())
    post(%{body: body}) ->
      {:ok, %{message: message}} = PublishForm.parse(body)
      {:ok, _} = ChatRoom.publish(message)
      redirect("/")
  end

  route "/updates" do
    get() ->
      {:ok, _} = ChatRoom.join()
      SSE.stream(:updates)
  end

  SSE.streaming :updates do
    {:message, message} ->
      {:send, %{event: "chat", data: "message"}
    _ ->
      {:nosend}
  end
end

Hopefully it the majority of the example is self explanatory.I hope to push the first version to hex soon

OvermindDL1

OvermindDL1

I subscribe to the Python credo of “Explicit is better than Implicit”. ^.^

Crowdhailer

Crowdhailer

Creator of Raxx

Final comment to close of this thread.

I have abandoned efforts to write a Sinatra style routing DSL. As any useful API must be documented I have decided to use that documentation as a router. My implementation of this is Raxx.Blueprint that will parse an API Blueprint file and generate forward requests to controllers based on that.

Where Next?

Popular in Discussions Top

sashaafm
I’m trying to evaluate the best combo/stack for a BEAM Web app. Right now I’m exploring Yaws a bit, after having dealt with Phoenix for a...
New
thojanssens1
It would be nice to be able to define a redirect from one route to another from the router.ex file. E.g.: redirect "/", UserController, ...
New
pillaiindu
I want to convert a Phoenix LiveView CRUD website to a CRUD mobile app. What do you think is the easiest way to do so?
New
PragTob
Hey everyone, this has been brewing in my head some time and it came up again while reading Adopting Elixir. GenServers, supervisors et...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
pdgonzalez872
If this has been asked here before, please point me to where it was asked as I didn’t find it when I searched the forum. Maybe a mailing ...
New
paulanthonywilson
I like Umbrella projects and pretty much always use them for personal Elixir stuff, especially Nerves things. But I don’t think this is ...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement