Current section

Files

Jump to
dream src dream@http@response.erl
Raw

src/dream@http@response.erl

-module(dream@http@response).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream/http/response.gleam").
-export([text_response/2, json_response/2, html_response/2, redirect_response/2, empty_response/1, binary_response/3, stream_response/3, sse_response/3]).
-export_type([response_body/0, response/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" HTTP response types and builders\n"
"\n"
" Core response types and convenient functions for building common HTTP responses.\n"
" This module provides builders for text, JSON, HTML, binary, and streaming responses.\n"
"\n"
" ## Quick Examples\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
"\n"
" // Text response\n"
" response.text_response(status.ok, \"Hello, World!\")\n"
"\n"
" // JSON response\n"
" response.json_response(status.ok, json.to_string(user_json))\n"
"\n"
" // HTML response\n"
" response.html_response(status.ok, \"<h1>Welcome</h1>\")\n"
"\n"
" // Redirect\n"
" response.redirect_response(status.see_other, \"/login\")\n"
" ```\n"
).
-type response_body() :: {text, binary()} |
{bytes, bitstring()} |
{stream, gleam@yielder:yielder(bitstring())}.
-type response() :: {response,
integer(),
response_body(),
list(dream@http@header:header()),
list(dream@http@cookie:cookie()),
gleam@option:option(binary())}.
-file("src/dream/http/response.gleam", 116).
?DOC(
" Create a plain text response\n"
"\n"
" Returns a response with `text/plain` content type.\n"
" Use for plain text output that isn't JSON, HTML, or another format.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response.{text_response}\n"
" import dream/http/status.{ok}\n"
"\n"
" pub fn healthcheck(request, context, services) {\n"
" text_response(ok, \"OK\")\n"
" }\n"
" ```\n"
).
-spec text_response(integer(), binary()) -> response().
text_response(Status, Body) ->
{response,
Status,
{text, Body},
[{header, <<"Content-Type"/utf8>>, <<"text/plain; charset=utf-8"/utf8>>}],
[],
{some, <<"text/plain; charset=utf-8"/utf8>>}}.
-file("src/dream/http/response.gleam", 148).
?DOC(
" Create a JSON response\n"
"\n"
" Returns a response with `application/json` content type.\n"
" Pass a JSON string (from `gleam/json` or similar). This function\n"
" doesn't encode JSON for you—use `gleam/json` to encode first.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response.{json_response}\n"
" import dream/http/status.{ok}\n"
" import gleam/json\n"
"\n"
" pub fn show_user(request, context, services) {\n"
" let user_json = json.object([\n"
" #(\"id\", json.int(123)),\n"
" #(\"name\", json.string(\"Alice\")),\n"
" ])\n"
" \n"
" json_response(ok, json.to_string(user_json))\n"
" }\n"
" ```\n"
).
-spec json_response(integer(), binary()) -> response().
json_response(Status, Body) ->
{response,
Status,
{text, Body},
[{header,
<<"Content-Type"/utf8>>,
<<"application/json; charset=utf-8"/utf8>>}],
[],
{some, <<"application/json; charset=utf-8"/utf8>>}}.
-file("src/dream/http/response.gleam", 180).
?DOC(
" Create an HTML response\n"
"\n"
" Returns a response with `text/html` content type.\n"
" Use for HTML pages, HTMX responses, or HTML fragments.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
"\n"
" pub fn index(request, context, services) {\n"
" let html = \"\n"
" <!DOCTYPE html>\n"
" <html>\n"
" <body><h1>Welcome</h1></body>\n"
" </html>\n"
" \"\n"
" \n"
" response.html_response(status.ok, html)\n"
" }\n"
" ```\n"
).
-spec html_response(integer(), binary()) -> response().
html_response(Status, Body) ->
{response,
Status,
{text, Body},
[{header, <<"Content-Type"/utf8>>, <<"text/html; charset=utf-8"/utf8>>}],
[],
{some, <<"text/html; charset=utf-8"/utf8>>}}.
-file("src/dream/http/response.gleam", 215).
?DOC(
" Create a redirect response\n"
"\n"
" Returns a redirect with the Location header set. Use with redirect\n"
" status codes (301, 302, 303, 307) to send the client to a new URL.\n"
"\n"
" Common patterns:\n"
" - `303 See Other`: After POST/PUT/DELETE, redirect to GET (prevents duplicate submission)\n"
" - `302 Found`: Temporary redirect (can change method)\n"
" - `301 Moved Permanently`: Permanent redirect (update bookmarks/search engines)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
"\n"
" pub fn create_post(request, context, services) {\n"
" // After creating post, redirect to view it\n"
" let post_id = 123\n"
" response.redirect_response(\n"
" status.see_other,\n"
" \"/posts/\" <> int.to_string(post_id)\n"
" )\n"
" }\n"
" ```\n"
).
-spec redirect_response(integer(), binary()) -> response().
redirect_response(Status, Location) ->
{response,
Status,
{text, <<""/utf8>>},
[{header, <<"Location"/utf8>>, Location}],
[],
none}.
-file("src/dream/http/response.gleam", 243).
?DOC(
" Create an empty response with no body\n"
"\n"
" Returns a response with no content. Commonly used with:\n"
" - `204 No Content`: Successful request with no data to return\n"
" - `404 Not Found`: Resource doesn't exist\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
"\n"
" pub fn delete_user(request, context, services) {\n"
" // After successful deletion, return 204 with no body\n"
" delete_from_db(services.db, user_id)\n"
" response.empty_response(status.no_content)\n"
" }\n"
" ```\n"
).
-spec empty_response(integer()) -> response().
empty_response(Status) ->
{response, Status, {text, <<""/utf8>>}, [], [], none}.
-file("src/dream/http/response.gleam", 274).
?DOC(
" Create a binary response for files, images, PDFs, etc.\n"
"\n"
" Returns a response with binary data. Use for images, PDFs, zip files,\n"
" or any non-text content. You must specify the content type.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
" import simplifile\n"
"\n"
" pub fn serve_image(request, context, services) {\n"
" case simplifile.read_bits(\"logo.png\") {\n"
" Ok(image_data) ->\n"
" response.binary_response(status.ok, image_data, \"image/png\")\n"
" Error(_) ->\n"
" response.empty_response(status.not_found)\n"
" }\n"
" }\n"
" ```\n"
).
-spec binary_response(integer(), bitstring(), binary()) -> response().
binary_response(Status, Body, Content_type) ->
{response,
Status,
{bytes, Body},
[{header, <<"Content-Type"/utf8>>, Content_type}],
[],
{some, Content_type}}.
-file("src/dream/http/response.gleam", 312).
?DOC(
" Create a streaming response for large files or real-time data\n"
"\n"
" Returns a response with a stream of chunks. Use for:\n"
" - Large files (stream without loading entire file in memory)\n"
" - Real-time data (AI responses, logs, events)\n"
" - CSV exports (generate rows on-demand)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
" import gleam/yielder\n"
"\n"
" pub fn export_users(request, context, services) {\n"
" let user_stream = \n"
" query_all_users(services.db)\n"
" |> yielder.from_list\n"
" |> yielder.map(user_to_csv_row)\n"
" |> yielder.map(fn(row) { <<row:utf8>> })\n"
" \n"
" response.stream_response(status.ok, user_stream, \"text/csv\")\n"
" }\n"
" ```\n"
).
-spec stream_response(integer(), gleam@yielder:yielder(bitstring()), binary()) -> response().
stream_response(Status, Stream, Content_type) ->
{response,
Status,
{stream, Stream},
[{header, <<"Content-Type"/utf8>>, Content_type}],
[],
{some, Content_type}}.
-file("src/dream/http/response.gleam", 355).
?DOC(
" Create a Server-Sent Events (SSE) response\n"
"\n"
" Returns a streaming response configured for Server-Sent Events.\n"
" SSE enables server-to-client real-time updates over HTTP.\n"
"\n"
" The response includes:\n"
" - `Content-Type: text/event-stream`\n"
" - `Cache-Control: no-cache`\n"
" - `Connection: keep-alive`\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/response\n"
" import dream/http/status\n"
" import gleam/yielder\n"
"\n"
" pub fn events(request, context, services) {\n"
" let event_stream = \n"
" subscribe_to_events(services)\n"
" |> yielder.map(format_sse_event)\n"
" \n"
" response.sse_response(status.ok, event_stream, \"text/event-stream\")\n"
" }\n"
"\n"
" fn format_sse_event(data: String) -> BitArray {\n"
" <<\"data: \", data:utf8, \"\\n\\n\":utf8>>\n"
" }\n"
" ```\n"
).
-spec sse_response(integer(), gleam@yielder:yielder(bitstring()), binary()) -> response().
sse_response(Status, Stream, Content_type) ->
{response,
Status,
{stream, Stream},
[{header, <<"Content-Type"/utf8>>, Content_type},
{header, <<"Cache-Control"/utf8>>, <<"no-cache"/utf8>>},
{header, <<"Connection"/utf8>>, <<"keep-alive"/utf8>>}],
[],
{some, Content_type}}.