Current section
Files
Jump to
Current section
Files
lib/nex/res.ex
defmodule Nex.Res do
@moduledoc """
Pipeline-style response builder for API routes.
An alternative to `Nex.json/2`, `Nex.html/2`, etc. that uses
Elixir pipe syntax to build responses incrementally.
## Examples
def get(req) do
Nex.Res.new()
|> Nex.Res.json(%{users: list_users()})
end
def post(req) do
Nex.Res.new()
|> Nex.Res.status(201)
|> Nex.Res.json(%{created: true})
end
def delete(req) do
Nex.Res.new()
|> Nex.Res.status(204)
|> Nex.Res.send("")
end
def get(req) do
Nex.Res.new()
|> Nex.Res.redirect("/login")
end
def get(req) do
Nex.Res.new()
|> Nex.Res.set_header("x-request-id", "abc123")
|> Nex.Res.status(200)
|> Nex.Res.json(%{ok: true})
end
"""
alias Nex.Response
@doc "Creates a new response with default values (200 OK, empty body)."
@spec new() :: Response.t()
def new, do: %Response{}
@doc "Sets the HTTP status code."
@spec status(Response.t(), non_neg_integer()) :: Response.t()
def status(%Response{} = res, code) when is_integer(code), do: %{res | status: code}
@doc "Sets a JSON response body and content type."
@spec json(Response.t(), term()) :: Response.t()
def json(%Response{} = res, data), do: %{res | body: data, content_type: "application/json"}
@doc "Sets an HTML response body and content type."
@spec html(Response.t(), String.t()) :: Response.t()
def html(%Response{} = res, content), do: %{res | body: content, content_type: "text/html"}
@doc "Sets a plain text response body and content type."
@spec text(Response.t(), String.t()) :: Response.t()
def text(%Response{} = res, content), do: %{res | body: content, content_type: "text/plain"}
@doc "Sets the response body without changing content type."
@spec send(Response.t(), term()) :: Response.t()
def send(%Response{} = res, body), do: %{res | body: body}
@doc "Sets a redirect response with Location header."
@spec redirect(Response.t(), String.t(), non_neg_integer()) :: Response.t()
def redirect(%Response{} = res, url, status \\ 302) do
%{res | status: status, body: "", headers: Map.put(res.headers, "location", url), content_type: "text/html"}
end
@doc "Sets a response header."
@spec set_header(Response.t(), String.t(), String.t()) :: Response.t()
def set_header(%Response{} = res, key, value) do
%{res | headers: Map.put(res.headers, key, value)}
end
end