Mflask
Mflask is a small, Flask-inspired web framework for Elixir built on top of Plug and Bandit. It provides a minimal, expressive routing DSL, simple response helpers, and a few convenience middleware modules so you can write tiny web apps with familiar patterns.
This README covers:
- Quick start
- Routing and response helpers
- Middleware
- Templates
-
Running example apps with the
mix mf.servetask - Testing
- Contributing and license
Quick start
Add mflask to your dependencies (if using this project as a dependency). For local development,
you can use the example app pattern or run a module directly with the included mix task.
Example minimal app:
-
Create a file
example_app.ex:
defmodule ExampleApp do
use Mflask
get "/" do
text(conn, "Hello, world!")
end
get "/hello/:name" do
name = path_param(conn, "name") || "friend"
html(conn, "<h1>Hello #{name}</h1>")
end
end-
Serve the app from the directory containing
example_app.ex:
# from the project root (or directory containing example_app.ex)
mix mf.serve . --port 4000
Open http://localhost:4000 to see the app.
Router and DSL
Mflask exposes a compact routing DSL inspired by Flask. Inside a module use Mflask to get
routing macros and helpers.
Supported route macros:
get "/path" do ... endpost "/path" do ... endput "/path" do ... endpatch "/path" do ... enddelete "/path" do ... endoptions "/path" do ... endhead "/path" do ... end
Path parameters:
-
Use
:namein the path to capture segments. -
Retrieve with
path_param(conn, "name")or access the internal assigns viaconn.assigns[:mflask_params].
Query and body helpers:
query_param(conn, "q", default)— returns the first value if multiple are present.body_param(conn, "k", default)andbody_params(conn)— require body-parsing middleware (see below).
Example:
defmodule UsersApp do
use Mflask
get "/users/:id" do
id = path_param(conn, "id")
json(conn, %{user_id: id})
end
get "/search" do
q = query_param(conn, "q", "")
json(conn, %{query: q})
end
endResponse helpers
Mflask provides helpers to send common response types:
text(conn, "hello", status \\ 200)— send plain text.html(conn, "<h1>Hi</h1>", status \\ 200)— send HTML.json(conn, data, status \\ 200)— send JSON (usesJason).redirect(conn, "/path", status \\ 302)— perform redirects.send_file(conn, path, status \\ 200)— send files with MIME detection.
These are imported automatically into router modules.
Middleware
Mflask supports composing plugs as middleware. Use Mflask.Router.plug/2 in a router to attach
middleware.
Included middleware:
Mflask.Middleware.BodyParser— JSON, urlencoded and multipart parsing (usesPlug.Parsers+Jason).Mflask.Middleware.Static— simple static file serving with:atand:fromoptions.Mflask.Middleware.Logger— simple request logging.
Example:
defmodule ApiApp do
use Mflask
# attach middleware for this router
Mflask.Router.plug(Mflask.Middleware.BodyParser)
Mflask.Router.plug(Mflask.Middleware.Logger)
post "/echo" do
json(conn, body_params(conn))
end
endNotes:
- Middleware are executed in the order they are declared.
- If a plug halts the connection, the router will not dispatch further routes.
-
The
BodyParsercurrently supportsapplication/jsonandapplication/x-www-form-urlencodedout of the box.
Templates
Mflask ships a small EEx-based helper Mflask.Template:
render(conn, template_path, assigns \\ [])— render a template file and send as HTML. Options includelayout:andstatus:.render_string(template_string, assigns_or_opts \\ [])— evaluate a template string.
When rendering a template with a layout:, the layout can reference <%= @inner_content %>.
Helpers ensure a couple of common assigns are present to avoid warnings.
Example:
inner = "<p>Inner content: <%= @name %></p>"
layout = "<html><body><%= @inner_content %><footer>v<%= @ver %></footer></body></html>"
full =
Mflask.Template.render_string(inner, assigns: [name: "Alice"])
|> then(fn content ->
Mflask.Template.render_string(layout, assigns: [inner_content: content, ver: "0.1"])
end)
Running example apps with mix mf.serve
The project includes a mix task mix mf.serve to load Elixir files from a directory and start a Bandit server.
Usage:
mix mf.serve [PATH] [--module MyApp] [--port 4000] [--ip 127.0.0.1]
# examples:
mix mf.serve examples/ # scan and pick a module to serve (prefers ExampleApp)
mix mf.serve . --module ExampleApp # explicitly serve ExampleApp from current dir
mix mf.serve examples/ --port 8080 # serve on port 8080Behavior:
-
Requires (
Code.require_file/1) all.ex/.exsfiles underPATH. -
Detects modules defined in those files and selects a module to serve (prefers
ExampleApp). -
Validates the chosen module exports
call/2(i.e. is Plug-compatible). - Starts Bandit and blocks until you stop it.
Security note: requiring arbitrary code will execute top-level code. Only run this task on trusted source trees.
Testing
This project uses ExUnit. Tests are split into focused files under test/:
Run the full test suite:
mix testTest helpers use
Plug.Testto simulate requests for most units.
Development notes
-
Supported Elixir versions: specified in
mix.exs. -
Key dependencies:
plug,bandit,jason,mime. - The router compiles route definitions into private handler functions and dispatch clauses.
-
The
Mflask.Requesthelpers provide small utilities to get query/path/body params and remote IP. -
The
Mflask.Responsehelpers sanitize values when encoding JSON to avoid errors with internal structures.
Contributing
Contributions are welcome. Suggested workflow:
- Fork the repository.
- Create a feature branch.
- Add or update tests when introducing behavior changes.
-
Run
mix testand ensure all tests pass. - Open a merge request describing the change.
Please follow idiomatic Elixir formatting (mix format) and keep commits focused.
License
Mflask is distributed under the GPL-3.0 license. See LICENSE.md for details.
Contact / Support
If you run into issues, report them through the project tracker. For quick questions, open an issue with a minimal reproduction.