taro
I took lessons from the last discussion and cobbled together an example as a proof-of-concept.
Mar demonstrates a Flask-like web dev interface powered by Plug on Bandit.
use Mar immediately makes a module a route. The user modules don’t need to report to an entry-point plug in the app. Library handles routing.
Normal defs defines the actions to the requests. So you can compose them Elixir way. Router matches them by their names and the HTTP methods.
defmodule MyApp do
use Mar
def get(), do: "Hello, world!"
end
path can be set. Default is "/" otherwise.
params declares allowed parameters alongside path parameters with :. Later it takes matching keys from conn.params and puts it in the actions.
Actions can return a string, a map for JSON, or a tuple being {status, headers, body}.
defmodule MyApp do
use Mar, path: "/post/:id", params: [:comment]
def get(%{id: id}) do
"You are reading #{id}"
end
def post(%{id: id, comment: comment}) do
%{
id: id,
comment: comment
}
end
def delete(%{id: _id}) do
{301, [location: "/"], nil}
end
end
Routes can interact with the library through Mar.Route protocol.
defmodule MyApp do
use Mar
def get(), do: "Hello, world!"
defimpl Mar.Route do
# Mar.Route.MyApp
def before_action(route) do
IO.inspect(route.conn.resp_body)
# => nil
route
end
def after_action(route) do
IO.inspect(route.conn.resp_body)
# => "Hello, world!"
route
end
end
end
Intention
While there are many possible approaches to helping adoption and facilitating learning, the challenge I tackle here is to nicely encapsulate Plug and reduce cognitive load for the users. @taro lacks the technical capability for something production-ready, this project waxes on top of Bandit with an escape hatch in an attempt to help you envision a light and intuitive web framework for Elixir.
The insight and guidance from the community is much appreciated:
Design
This library relies on protocol consolidation to handle routes. use Mar injects a default defimpl of Mar.Route protocol. It lists up the user modules. At the same time, defstruct saves the path as a default struct value. Then the list of implementation maps to structs, which has information for path-matching.
case Mar.Route.__protocol__(:impls) do
{:consolidated, modules} -> Enum.map(modules, &struct(&1))
:not_consolidated -> []
end
# [
# %MyApp{ path: "/", ...},
# %MyApp.Post{ path: "/post/:id/", ...}, ,
# ...
# ]
Mar.Router leaves escape hatches open with the Mar.Route protocol. The user modules redefine the functions with defimpl to access them.
# Mar.Router
def call(conn, _options) do
# Match routes, load params
route = Mar.Route.before_action(route)
# Apply action
route = Mar.Route.after_action(route)
# Send response
end
Atom keys are preferred over string keys for the sake of nicer syntax. That’s also why params need to be declared so the library can prevent dynamic atom creation.
What do you think? I’m hoping to hear from you! ![]()
Reference
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex












Showing Posts 40 to 31- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
taro
Exactly! I’m using bare Plug, HTMX, and Temple now.
I’m not actively working on this topic. But I will when the time is right. Thanks!
edit: Datastar sounds like an upgrade from HTMX. Cool stuff, thanks!
jam
Maybe it could use
templefor an all-elixir feel. Something like this:jam
Another idea for you: pair Mar with data-star. Brand it as the simplest way to build fullstack, realtime Elixir apps.
jam
I like this. It’d be cool if you extended this idea for a channel router as well, maybe borrowing ideas from ChannelHandler with some adjustments on the syntax to fit Mar.
taro
Oh I appreciate every single comment. I read and learn and take notes from all of them. Thanks for sharing your wisdom. I hope moderators are happy too. Your off-topics are inspiring. I took a note of DSL for text protocols.
Please speak up. Difference is the very reason we should be talking. It’s probably only thing I’m bringing to this community. No one has to get dissuaded. I appreciate that you have chimed in when it’s rainy. I have my hopes for Elixir adoption. But I can’t do it alone. So I started the discussions in this community.
I started web development learning SvelteJS. SvelteKit is amazing in its way but there was not enough batteries included for my project. I wanted to learn a major framework and an awesomer language. Found Phoenix on Fly.io and Elixir was perfect. I understand the benefits and wisdom behind full-scale frameworks just that much.
As I come from more design disciplines, I find some software development practices are destined to overload one’s cognitive capacity. They would diverge into infinity without coming back to a simple principle. When it hits the critical point, it becomes an abomination that no one understands. And I see the effort to mitigate this in, for example Saša’s Boundary and his posts.
The source of this complexity doesn’t seem trivial and I haven’t fully explored this. But I wonder if it’s rooted to the file system of OS? Files are often grouped by their categories in a project, instead of their context.
spawnfeels weird to me because among all the functions that describe logics and data flow, it describes processes, which feels like another dimension of the system. Yet they are all written and managed the same way in the files of the directory system.dimitarvp
I use Live Grep in my IDE as well.
But I want to be able to fit a small app into one screen. For me it’s a hard requirement.
Thanks for engaging.
gregvaughn
You absolutely are. However …
This does not resonate with me. I almost never notice the organization of source code on the file system any more. I don’t have anything to offer to help. So, that’s why I’m bowing out of the conversation.
dimitarvp
@taro Sorry for off-topic, got carried away.
@AstonJ feel free to separate comments in an off-topic thread if you feel it must be done. I simply enjoy chatting with @gregvaughn so much. Or if not, feel free to delete this comment because it is definitely off-topic.
dimitarvp
Hm, I am not sure why you brought different programming languages / frameworks into this but I don’t disagree with what you said there either.
Sure. Same here. But I will gradually, over time, be chasing after using technology that spares my brain. Currently the amount of files I have to follow in order to be truly productive in Phoenix is unacceptable for me. Nobody has to agree but I’ve experimented all over the spectrum and “less files” is my best productivity enabler so far.
And as mentioned a few times, I don’t work with Phoenix’s specifics every day, I am a backender / data guy / CLI tools encyclopaedia and an alright Linux sysadmin – and I’ve never been impressed by almost any web framework; they leak too much of HTTP’s idiosyncrasies into what should be strictly business domain code, and Phoenix is no exception.
But I think we as senior devs understand that leaky abstractions are one of the most difficult problems to solve. Hence I don’t complain too much and do my best to keep discussions on the topic productive because I know this stuff is mega-hard.
But I’m free to pursue ways of doing stuff that make me smile, be excited about programming again, and also be productive – because as much as I love flinging characters on the screen, I also want to make money and not be a hobby computer nerd until my grave. There are many more things to life than this that also make it a joy to live through, and trying to be more productive is one way to help us pursue those instead (== less hours in front of a screen), and not the ever-elusive 100% mastery.
gregvaughn
No, it’s still not full agreement. While I agree there are apps that never need scale, we, as a software engineering community, are horrible at predicting this. I don’t trust any of us, not even myself. For something that we don’t think will need to scale, let’s add a new controller to an existing Phoenix app. However, if the company has no existing Elixir in production, my opinion is that it’s a bad idea to introduce a small endpoint that’ll never scale to their portfolio of technologies. As much as I love Elixir and want to see it grow, it does not leave a good impression as “that one app the passionate engineer talked us into trying, then left us with no one else to maintain it”.