filipecabaco

filipecabaco

Francis - Sinatra-style HTTP / WebSocket / SSE on Plug + Bandit

Hi everyone,

I’ve been working on Francis, a lightweight framework built on top of Plug and Bandit that tries to get you from idea to a running endpoint with as little ceremony as possible. Think Sinatra for Elixir.

What it is

You use Francis in a module, define routes with get/post/ws/sse, and you have a running server. No routers, no controllers, no context boilerplate, just a function per route.

defmodule MyApp do
  use Francis

  get "/", fn _ -> %{hello: :world} end
  get "/:name", fn %{params: %{"name" => name}} -> "hello #{name}" end
  post "/", fn conn -> conn.body_params end

  ws "/chat", fn
    :join, socket -> {:reply, "welcome"}
    {:received, msg}, _ -> {:reply, msg}
  end

  sse "/events", fn
    :join, socket -> {:reply, %{id: socket.id}}
    {:received, m}, _ -> {:reply, m}
  end

  unmatched fn _ -> "not found" end
end

Return a string and it renders as HTML. Return a map and it renders as JSON. Return a Plug.Conn for full control.

Get started

mix archive.install hex francis
mix francis.new my_app
cd my_app
mix francis.server

Or add to an existing project:

{:francis, “~> 0.3”}

If you use Claude Code, install the Francis skill for route patterns, SSE/WS gotchas, and security guidance:

npx skills add francis-build/francis@francis-thinking

Links


Curious what the community thinks. It is not trying to replace Phoenix, it is for when you want something closer to raw Plug without writing the same boilerplate every time. Happy to answer questions.

Most Liked

filipecabaco

filipecabaco

Ok I did try out and it does work as you said :+1: since it’s just Plug it’s all good

defmodule PhoenixEmbedWeb.Router do
  use PhoenixEmbedWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {PhoenixEmbedWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", PhoenixEmbedWeb do
    pipe_through :browser

    get "/", PageController, :home
  end

  # Forward all /api requests to the Francis API router.
  # Phoenix strips the /api prefix, so Francis routes are relative (e.g. /items).
  forward "/api", PhoenixEmbedWeb.FrancisApi
end
josefrichter

josefrichter

Thanks for Francis @filipecabaco ! Always loved Sinatra for prototyping and side projects, so I love Francis by definition.

So much so that I just migrated my personal website https://josefrichter.design to it, and added a simple chat widget there using Francis’ SSE, telegram bot and Mac widget.

Also created francis_template | Hex in the process, because I needed it and the francis_htmx didn’t fit my needs.

filipecabaco

filipecabaco

Thank you so much! Really glad to hear that.

I need to rethink fully francis_htmx as it really got way out of hand in complexity which was a sign of bad implementation :sweat_smile:

Will check francis_template. I do like the idea as again follows the same ideas as francis - boilerplate reduction :heart:

Where Next?

Popular in Announcing Top

wmnnd
Hi there, for my project DBLSQD, I needed a file storage solution that is a bit more flexible than Arc. Because I thought others might f...
New
ostinelli
Let’s write a database! Well not really, but I think it’s a little sad that there doesn’t seem to be a simple in-memory distributed KV da...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New
kip
Image is an image processing library for Elixir. It is based upon the fabulous vix library that provides a libvips wrapper for Elixir. I...
622 18934 194
New
ahamez
Hi everyone, I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
cjen07
parameterized pipe in elixir: |n> edit: negative index in |n> and mixed usage with |> are supported example: use ParamPipe ...
New
Jskalc
Hi! Today, after a couple weeks of development I’ve released v0.1 of LiveVue. It’s a seamless integration of Vue and Phoenix LiveView, i...
New
marcuslankenau
I feel kind of stuck with the absence of a proper xml library for Elixir. Currently I use SweetXML which was ok for me more or less to pa...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
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
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41989 114
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52673 488
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement