Current section

Files

Jump to
dream src dream@servers@mist@server.erl
Raw

src/dream@servers@mist@server.erl

-module(dream@servers@mist@server).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream/servers/mist/server.gleam").
-export([new/0, context/2, services/2, router/2, bind/2, max_body_size/2, listen/2, listen_without_blocking/2]).
-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(
" Your Dream app's entry point\n"
"\n"
" This module is where your web application starts. It provides a builder pattern\n"
" for configuring and starting a Dream server using Mist (the BEAM's HTTP server).\n"
"\n"
" ## Quick Start\n"
"\n"
" ```gleam\n"
" import dream/servers/mist/server.{listen, router}\n"
" \n"
" pub fn main() {\n"
" server.new()\n"
" |> router(create_router())\n"
" |> listen(3000)\n"
" }\n"
" ```\n"
"\n"
" The builder pattern lets you configure your server step by step. Start with `new()`,\n"
" add your router, and optionally set custom context and services before calling `listen()`.\n"
"\n"
" ## Custom Context and Services\n"
"\n"
" By default, Dream uses `EmptyContext` (no per-request data) and `EmptyServices` (no shared\n"
" dependencies). For most production apps, you'll want to define your own types:\n"
"\n"
" ```gleam\n"
" import dream/servers/mist/server.{context, listen, router, services}\n"
" import gleam/option.{None}\n"
" \n"
" pub type MyContext {\n"
" MyContext(request_id: String, user: option.Option(User), session: Session)\n"
" }\n"
"\n"
" server.new()\n"
" |> context(MyContext(request_id: \"\", user: None, session: empty_session()))\n"
" |> services(initialize_services())\n"
" |> router(create_router())\n"
" |> listen(3000)\n"
" ```\n"
"\n"
" The type system ensures your controllers receive the correct context type.\n"
).
-file("src/dream/servers/mist/server.gleam", 82).
?DOC(
" Create a new Dream server with defaults\n"
"\n"
" Returns a server configured with `EmptyContext` (no per-request data) and\n"
" `EmptyServices` (no dependencies). For simple applications, you only need to add\n"
" a router. For more complex apps, use `context()` and `services()` to provide your\n"
" own types before calling `listen()`.\n"
"\n"
" ## Simple Example (no context or services)\n"
"\n"
" ```gleam\n"
" import dream/servers/mist/server.{listen, router}\n"
" \n"
" server.new()\n"
" |> router(my_router)\n"
" |> listen(3000)\n"
" ```\n"
"\n"
" ## With Custom Context and Services\n"
"\n"
" ```gleam\n"
" import dream/servers/mist/server.{context, listen, router, services}\n"
" import gleam/option.{None}\n"
" \n"
" server.new()\n"
" |> context(MyContext(request_id: \"\", user: None))\n"
" |> services(my_services)\n"
" |> router(my_router)\n"
" |> listen(3000)\n"
" ```\n"
).
-spec new() -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), dream@context:empty_context(), dream@router:empty_services()).
new() ->
{dream, mist:new(fun(_) -> _pipe = gleam@http@response:new(404),
gleam@http@response:set_body(
_pipe,
{bytes, gleam@bytes_tree:new()}
) end), none, empty_context, {some, empty_services}, 9223372036854775807}.
-file("src/dream/servers/mist/server.gleam", 119).
?DOC(
" Set a custom context type for your application\n"
"\n"
" Use this to replace `AppContext` with your own context type that holds\n"
" user authentication, session data, or any other per-request information.\n"
" The type system tracks your context through middleware and controllers.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub type MyContext {\n"
" MyContext(request_id: String, user: Option(User))\n"
" }\n"
"\n"
" dream.new()\n"
" |> dream.context(MyContext(request_id: \"\", user: None))\n"
" |> dream.services(my_services)\n"
" |> dream.router(my_router)\n"
" |> dream.listen(3000)\n"
" ```\n"
).
-spec context(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), any(), AEHO),
AEHS
) -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEHS, AEHO).
context(Dream_instance, New_context) ->
{dream,
erlang:element(2, Dream_instance),
none,
New_context,
erlang:element(5, Dream_instance),
erlang:element(6, Dream_instance)}.
-file("src/dream/servers/mist/server.gleam", 159).
?DOC(
" Provide your application's services\n"
"\n"
" Services are shared dependencies available to all requests—database connections,\n"
" HTTP clients, caches, etc. Define a type that holds all your services and pass it here.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub type Services {\n"
" Services(db: Connection, cache: Cache)\n"
" }\n"
"\n"
" pub fn initialize_services() -> Services {\n"
" let db = connect_to_database()\n"
" let cache = create_cache()\n"
" Services(db: db, cache: cache)\n"
" }\n"
"\n"
" dream.new()\n"
" |> dream.services(initialize_services())\n"
" |> dream.router(my_router)\n"
" |> dream.listen(3000)\n"
" ```\n"
).
-spec services(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEIA, dream@router:empty_services()),
AEIE
) -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEIA, AEIE).
services(Dream_instance, Services_instance) ->
{dream,
erlang:element(2, Dream_instance),
none,
erlang:element(4, Dream_instance),
{some, Services_instance},
erlang:element(6, Dream_instance)}.
-file("src/dream/servers/mist/server.gleam", 195).
?DOC(
" Provide your application's router\n"
"\n"
" The router defines which controllers handle which requests. It must be configured\n"
" with the same context and services types you've set up, which the type system enforces.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub fn create_router() -> Router(MyContext, Services) {\n"
" router.new\n"
" |> router.get(\"/\", controllers.index)\n"
" |> router.get(\"/users/:id\", controllers.show_user)\n"
" }\n"
"\n"
" dream.new()\n"
" |> dream.services(initialize_services())\n"
" |> dream.router(create_router())\n"
" |> dream.listen(3000)\n"
" ```\n"
).
-spec router(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEIM, AEIN),
dream@router:router(AEIM, AEIN)
) -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEIM, AEIN).
router(Dream_instance, Router_instance) ->
{dream,
erlang:element(2, Dream_instance),
{some, Router_instance},
erlang:element(4, Dream_instance),
erlang:element(5, Dream_instance),
erlang:element(6, Dream_instance)}.
-file("src/dream/servers/mist/server.gleam", 227).
?DOC(
" Set the network interface to bind to\n"
"\n"
" Defaults to binding to all interfaces. Use \"localhost\" or \"127.0.0.1\" to only\n"
" accept local connections, or \"0.0.0.0\" to accept connections from any network interface.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" // Only accept local connections\n"
" dream.new()\n"
" |> dream.services(my_services)\n"
" |> dream.router(my_router)\n"
" |> dream.bind(\"localhost\")\n"
" |> dream.listen(3000)\n"
" ```\n"
).
-spec bind(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEJA, AEJB),
binary()
) -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEJA, AEJB).
bind(Dream_instance, Interface) ->
{dream,
mist:bind(erlang:element(2, Dream_instance), Interface),
erlang:element(3, Dream_instance),
erlang:element(4, Dream_instance),
erlang:element(5, Dream_instance),
erlang:element(6, Dream_instance)}.
-file("src/dream/servers/mist/server.gleam", 256).
?DOC(
" Set maximum request body size in bytes\n"
"\n"
" Requests with bodies larger than this will be rejected. Default is effectively\n"
" unlimited (max 64-bit int). Set a reasonable limit to protect against memory exhaustion.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" // Limit request bodies to 10MB\n"
" dream.new()\n"
" |> dream.services(my_services)\n"
" |> dream.router(my_router)\n"
" |> dream.max_body_size(10_000_000)\n"
" |> dream.listen(3000)\n"
" ```\n"
).
-spec max_body_size(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEJM, AEJN),
integer()
) -> dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), AEJM, AEJN).
max_body_size(Dream_instance, Size) ->
{dream,
erlang:element(2, Dream_instance),
erlang:element(3, Dream_instance),
erlang:element(4, Dream_instance),
erlang:element(5, Dream_instance),
Size}.
-file("src/dream/servers/mist/server.gleam", 271).
?DOC(
" Helper function to update context with request_id\n"
" This is a simple implementation that just returns the template context\n"
" Most applications don't need request_id in their context\n"
" If you need request_id, consider using middleware or logging\n"
).
-spec update_context_with_request_id(AEJW, binary()) -> AEJW.
update_context_with_request_id(Ctx, _) ->
Ctx.
-file("src/dream/servers/mist/server.gleam", 308).
?DOC(
" Internal function to start the server with configurable blocking behavior\n"
" Used by listen (blocks forever) and listen_without_blocking (for testing)\n"
).
-spec listen_internal(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), any(), any()),
integer(),
boolean()
) -> nil.
listen_internal(Dream_instance, Port, Block_forever) ->
Router_instance@1 = case erlang:element(3, Dream_instance) of
{some, Router_instance} -> Router_instance;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"dream/servers/mist/server"/utf8>>,
function => <<"listen_internal"/utf8>>,
line => 318,
value => _assert_fail,
start => 9345,
'end' => 9408,
pattern_start => 9356,
pattern_end => 9384})
end,
Services_instance@1 = case erlang:element(5, Dream_instance) of
{some, Services_instance} -> Services_instance;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"dream/servers/mist/server"/utf8>>,
function => <<"listen_internal"/utf8>>,
line => 319,
value => _assert_fail@1,
start => 9411,
'end' => 9478,
pattern_start => 9422,
pattern_end => 9452})
end,
Handler_fn = dream@servers@mist@handler:create(
Router_instance@1,
erlang:element(6, Dream_instance),
erlang:element(4, Dream_instance),
Services_instance@1,
fun update_context_with_request_id/2
),
Server_with_handler = mist:new(Handler_fn),
Server_with_port = mist:port(Server_with_handler, Port),
case mist:start(Server_with_port) of
{ok, _} ->
case Block_forever of
true ->
gleam_erlang_ffi:sleep_forever();
false ->
nil
end;
{error, _} ->
nil
end.
-file("src/dream/servers/mist/server.gleam", 295).
?DOC(
" Start the server and listen for requests\n"
"\n"
" Starts the server on the specified port and blocks forever. This is what you call\n"
" in your `main()` function. If the server fails to start, it returns `Nil` immediately.\n"
"\n"
" This function will panic if you haven't called `router()` and `services()` first—\n"
" you can't run a web server without defining what it does.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub fn main() {\n"
" dream.new()\n"
" |> dream.services(initialize_services())\n"
" |> dream.router(create_router())\n"
" |> dream.listen(3000)\n"
" }\n"
" ```\n"
).
-spec listen(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), any(), any()),
integer()
) -> nil.
listen(Dream_instance, Port) ->
listen_internal(Dream_instance, Port, true).
-file("src/dream/servers/mist/server.gleam", 369).
?DOC(
" Start the server without blocking\n"
"\n"
" Like `listen()`, but returns immediately instead of blocking forever. Useful for\n"
" tests where you need the server running in the background so you can make requests to it.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" pub fn test_server() {\n"
" // Start server in background\n"
" dream.new()\n"
" |> dream.services(test_services())\n"
" |> dream.router(test_router())\n"
" |> dream.listen_without_blocking(8080)\n"
" \n"
" // Make test requests\n"
" let response = http_client.get(\"http://localhost:8080/test\")\n"
" // ... assertions ...\n"
" }\n"
" ```\n"
).
-spec listen_without_blocking(
dream@dream:dream(mist:builder(mist@internal@http:connection(), mist:response_data()), any(), any()),
integer()
) -> nil.
listen_without_blocking(Dream_instance, Port) ->
listen_internal(Dream_instance, Port, false).