Tamnoon - Realtime web apps with any frontend and 0 effort :)

Hey all!

A little background for this: as much as I love Elixir, I suck at UI design. Not even CSS - I just can’t make a nice UI without my comfy Joy UI components. And I’m sure I’m not the only one :grin:
I wanted to get into web dev with Elixir, but the more I looked into it the more it seemed just… extra. I’m just a high schooler making web apps, I don’t need big crazy frameworks with databases. And I’m sure I’m not the only one :)))

So I made Tamnoon - a library (/framework i guess?) to make realtime web apps effortlessly without all the bells and whistles. It’s basically a glorified cowboy websocket server, and it’s pretty much fully extensible, so you can do anything you want with it really.

I aimed to make it as simple as possible and abstract everything away, including the boilerplate - so you can write clean readable code with 0 distractions.

By default it is capable of holding a state for each client (similar to agents) and also implements basic pubsub functionality with channels. (currently no built-in database support since I do not get along with databases :innocent:)

The guides in the documentation basically cover everything you need to know, so check them out if you’re interested! Tamnoon v0.1.1 — Documentation

I would love to hear if you tried it out, and in general any thoughts / questions about it :slight_smile:
Hope you have a great day!

2 Likes

Looks like building http servers has become a hobby of many lately.

Can you highlight how your solution is in any way better/easier that using Plug + Phoenix Channels?

0 setup, 0 boilerplate, 0 complexity. It’s also specifically made for this whereas with phoenix it’s more general purpose, which while it can be very beneficial also means tons of unnecessary boilerplate.

for example, to create a chat app you simply add Tamnoon to your supervision tree like so:

{Tamnoon, [[initial_state: %{last_message: ""}]]}

and that’s literally it for the backend. just have the frontend show new messages as the last_message value changes, and send this json for sending new messages:

{
  "method": "pub",
  "channel": "clients",
  "action": {
    "method": "update",
    "key": "last_message",
    "val": "the new message"
  }
}

PS. Sorry if the formatting is bad, I’m just on my phone rn

1 Like

Took a quick look at your tutorial. Seems to be revolving mostly around in-memory storage with optional shared state for all clients which is OK. Not a super widespread use-case but it’s nice to have some alternatives.

Thanks :slight_smile:

Yeah I’m honestly not a huge fan of dealing with databases, however it shouldn’t be hard to add data storage with ecto (or even just straight up json files)

I am a fan of frameworks with much less files than Phoenix – though indeed it’s hard to argue that Phoenix puts too many files; I’d merge or even eliminate some but it’s true that most are indeed necessary, at least in terms of how Phoenix itself works.

There is a much bigger thread on this topic which is also IMO very relevant to your framework, here: https://elixirforum.com/t/a-simpler-web-framework-without-plug-phoenix/62885

Ooh thanks, I actually took some inspiration from that framework :grin: I’ll add a little comment there

And yeah I agree about Phoenix - it makes it even more complicated imo, as you actually need to know what each file is for and everything.

It took me a while to understand what Tamnoon does tbh. I don’t think the comparison to “big crazy frameworks” does you a favor here, as Tamnoon is providing but a tiny sliver of what you’d generally do with those big frameworks.

I really like the idea though. What Tamnoon provides on top of its dependencies is basically CRUD + pubsub of state on the server to clients connected via websockets + extension points for custom actions. This sounds like a great prototyping option when all you care for on the server is that it can hold and manipulate some shared state while working on the frontend.

I might want to look at Bare Websockets | Benjamin Milde, which would allow you to use plug for the websocket portion of tamnoon as well. So Tamnoon could work with both cowboy and bandit as underlying webserver.

2 Likes

Thanks! Yeah that’s basically the gist of it. Originally my concept was just to “imitate” everything I do in React that isn’t inside a React component (so for example api stuff or more complex functions in general).

And I looked at that, and while I don’t know if it would really fit the whole simplicity idea of Tamnoon (and I also don’t think it would necessarily provide that much more functionality that custom methods can’t) it does give me an idea - maybe allowing methods to be “piped” into others would be useful. Like Plug pipelines (but from the json requests instead of the elixir code).