Getting Started with Rocket
Setup
Mix.install([
{:rocket, path: Path.join(__DIR__, "..")},
{:req, "~> 0.5"}
])
Hello World
The simplest Rocket app: a single GET route that returns text.
defmodule HelloRouter do
use Rocket.Router
get "/hello" do
send_resp(req, 200, "Hello from Rocket!")
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, hello_sup} = Rocket.start_link(port: 14_001, handler: HelloRouter)
Req.get!("http://127.0.0.1:14001/hello").body
# Non-existent route returns 404
Req.get!("http://127.0.0.1:14001/nope").status
Supervisor.stop(hello_sup)
Path Parameters
Route segments prefixed with : become path parameters, accessible via req.path_params.
defmodule PathParamsRouter do
use Rocket.Router
get "/users/:id" do
json(req, 200, %{user_id: req.path_params["id"]})
end
get "/repos/:owner/:repo" do
json(req, 200, %{
owner: req.path_params["owner"],
repo: req.path_params["repo"]
})
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, path_sup} = Rocket.start_link(port: 14_002, handler: PathParamsRouter)
Req.get!("http://127.0.0.1:14002/users/42").body
Req.get!("http://127.0.0.1:14002/repos/elixir-lang/elixir").body
Supervisor.stop(path_sup)
Query Parameters
Use Rocket.Request.query_params/1 to parse the full query string, or
Rocket.Request.get_query_param/2 to grab a single key.
defmodule QueryRouter do
use Rocket.Router
get "/search" do
{params, _req} = Rocket.Request.query_params(req)
json(req, 200, params)
end
get "/greeting" do
name = Rocket.Request.get_query_param(req, "name") || "world"
send_resp(req, 200, "Hello, #{name}!")
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, query_sup} = Rocket.start_link(port: 14_003, handler: QueryRouter)
Req.get!("http://127.0.0.1:14003/search?metric=cpu&host=web-1®ion=us-east").body
Req.get!("http://127.0.0.1:14003/greeting?name=Rocket").body
# Falls back to default when param is absent
Req.get!("http://127.0.0.1:14003/greeting").body
Supervisor.stop(query_sup)
JSON API
json/3 encodes an Elixir term as JSON and sets the content-type header automatically.
Request bodies are available as req.body.
defmodule JsonApiRouter do
use Rocket.Router
get "/status" do
json(req, 200, %{status: "healthy", uptime_ms: System.monotonic_time(:millisecond)})
end
post "/echo" do
decoded = :json.decode(req.body)
json(req, 200, %{received: decoded})
end
post "/size" do
json(req, 200, %{bytes: byte_size(req.body)})
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, json_sup} = Rocket.start_link(port: 14_004, handler: JsonApiRouter)
Req.get!("http://127.0.0.1:14004/status").body
Req.post!("http://127.0.0.1:14004/echo", json: %{hello: "world"}).body
Req.post!("http://127.0.0.1:14004/size", body: String.duplicate("x", 1024)).body
Supervisor.stop(json_sup)
Custom Headers
Rocket.Response.send_iodata/4 lets you set arbitrary response headers — useful for
CSV, HTML, or any non-JSON content type.
defmodule CustomHeadersRouter do
use Rocket.Router
get "/csv" do
csv = "name,score\nAlice,95\nBob,87\nCharlie,92\n"
send_iodata(req, 200, [{"content-type", "text/csv"}, {"x-row-count", "3"}], csv)
end
get "/html" do
html = "Rocket
A fast HTTP server for Elixir.
"
send_iodata(req, 200, [{"content-type", "text/html; charset=utf-8"}], html)
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, headers_sup} = Rocket.start_link(port: 14_005, handler: CustomHeadersRouter)
resp = Req.get!("http://127.0.0.1:14005/csv")
IO.puts(resp.body)
IO.inspect(resp.headers)
Req.get!("http://127.0.0.1:14005/html").body
Supervisor.stop(headers_sup)
Configuration
Rocket accepts these options when starting a server:
| Option | Default | Description |
|---|---|---|
:handler |
required |
Module using Rocket.Router |
:port |
8080 |
TCP port |
:num_acceptors |
System.schedulers_online() |
Acceptor pool size |
:max_connections |
10_000 |
Max concurrent connections |
:max_body |
1_048_576 (1 MB) |
Max request body in bytes |
:backlog |
1024 |
TCP listen backlog |
defmodule ConfigRouter do
use Rocket.Router
get "/ping" do
send_resp(req, 200, "pong")
end
post "/upload" do
json(req, 200, %{received_bytes: byte_size(req.body)})
end
match _ do
send_resp(req, 404, "not found")
end
end
{:ok, config_sup} =
Rocket.start_link(
port: 14_006,
handler: ConfigRouter,
num_acceptors: 4,
max_connections: 100,
max_body: 2048,
backlog: 128
)
Req.get!("http://127.0.0.1:14006/ping").body
# Body within the 2KB limit succeeds
Req.post!("http://127.0.0.1:14006/upload", body: String.duplicate("a", 2000)).body
# Body exceeding the 2KB limit gets rejected (413 Content Too Large)
Req.post!("http://127.0.0.1:14006/upload", body: String.duplicate("a", 3000)).status
Supervisor.stop(config_sup)
Cleanup
All servers have been stopped in their respective sections. If you re-ran cells out of order and have leftover processes, you can stop them here:
for {pid, _} <- [
{hello_sup, nil},
{path_sup, nil},
{query_sup, nil},
{json_sup, nil},
{headers_sup, nil},
{config_sup, nil}
],
is_pid(pid) and Process.alive?(pid) do
Supervisor.stop(pid)
end
:ok