Packages

A focused, type-safe HTTP router for Gleam on BEAM — declarative routing, typed path params, middleware, wildcards, reverse routing, and testing helpers.

Current section

Files

Jump to
radiant src radiant.erl
Raw

src/radiant.erl

-module(radiant).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/radiant.gleam").
-export([int/1, str/1, key/1, fallback/2, middleware/2, mount/3, routes/1, path_for/2, path_for1/3, path_for2/5, path_for3/7, path_for4/9, path_for5/11, path_for6/13, get/3, post/3, put/3, patch/3, delete/3, options/3, any/3, get1/4, post1/4, put1/4, patch1/4, delete1/4, get2/5, post2/5, put2/5, patch2/5, delete2/5, get3/6, post3/6, put3/6, patch3/6, delete3/6, get4/7, post4/7, put4/7, patch4/7, delete4/7, get5/8, post5/8, put5/8, patch5/8, delete5/8, get6/9, post6/9, put6/9, patch6/9, delete6/9, method/1, req_path/1, header/2, headers/1, body/1, text_body/1, str_param/2, int_param/2, queries/1, 'query'/2, query_int/2, query_float/2, query_bool/2, original/1, set_context/3, get_context/2, response/2, ok/1, created/1, no_content/0, not_found/0, new/0, scope/3, bad_request/0, unauthorized/0, forbidden/0, unprocessable_entity/0, internal_server_error/0, bad_request_with/1, unauthorized_with/1, forbidden_with/1, not_found_with/1, unprocessable_entity_with/1, internal_server_error_with/1, redirect/1, with_header/3, method_not_allowed/1, handle/2, handle_with/3, json_error/2, json/1, html/1, default_cors/0, cors/1, log/1, rescue/1, json_body/2, serve_static/3, test_request/2, test_get/1, test_post/2, test_put/2, test_patch/2, test_delete/1, test_head/1, test_options/1, should_have_status/2, should_have_body/2, should_have_header/3, should_have_json_body/2]).
-export_type([router/0, file_system/0, req/0, key/1, param/1, cors_config/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(
" A trie-based HTTP router for Gleam on BEAM.\n"
" One import, no sub-modules. See the [README](https://hexdocs.pm/radiant/) for examples.\n"
).
-opaque router() :: {router,
radiant@internal@tree:node_(fun((req()) -> gleam@http@response:response(bitstring()))),
fun((req()) -> gleam@http@response:response(bitstring())),
list(fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))))}.
-type file_system() :: {file_system,
fun((binary()) -> {ok, bitstring()} | {error, nil}),
fun((binary()) -> boolean())}.
-opaque req() :: {req,
gleam@http@request:request(bitstring()),
gleam@dict:dict(binary(), binary()),
gleam@dict:dict(binary(), gleam@dynamic:dynamic_())}.
-opaque key(PDB) :: {key, binary()} | {gleam_phantom, PDB}.
-opaque param(PDC) :: {param,
binary(),
fun((binary()) -> {ok, PDC} | {error, nil}),
radiant@internal@path:param_type(),
fun((PDC) -> binary())}.
-type cors_config() :: {cors_config,
list(binary()),
list(gleam@http:method()),
list(binary()),
integer()}.
-file("src/radiant.gleam", 98).
?DOC(
" A `Param(Int)` that matches only integer path segments.\n"
" For use with `get1`, `get2`, `get3`, etc.\n"
"\n"
" ```gleam\n"
" router |> radiant.get1(\"/users/:id\", radiant.int(\"id\"), fn(req, id) {\n"
" radiant.ok(int.to_string(id)) // id: Int, guaranteed\n"
" })\n"
" ```\n"
).
-spec int(binary()) -> param(integer()).
int(Name) ->
{param,
Name,
fun gleam_stdlib:parse_int/1,
int_t,
fun erlang:integer_to_binary/1}.
-file("src/radiant.gleam", 115).
?DOC(
" A `Param(String)` that matches any path segment.\n"
" For use with `get1`, `get2`, `get3`, etc.\n"
"\n"
" ```gleam\n"
" router |> radiant.get1(\"/posts/:slug\", radiant.str(\"slug\"), fn(req, slug) {\n"
" radiant.ok(slug) // slug: String, no extraction needed\n"
" })\n"
" ```\n"
).
-spec str(binary()) -> param(binary()).
str(Name) ->
{param, Name, fun(S) -> {ok, S} end, string_t, fun(S@1) -> S@1 end}.
-file("src/radiant.gleam", 136).
?DOC(
" Create a typed context key. Pair with `set_context` and `get_context`\n"
" for type-safe request context passing through middlewares.\n"
"\n"
" ```gleam\n"
" pub const user_key: radiant.Key(User) = radiant.key(\"user\")\n"
"\n"
" // In middleware:\n"
" radiant.set_context(req, user_key, authenticated_user)\n"
"\n"
" // In handler:\n"
" let assert Ok(user) = radiant.get_context(req, user_key)\n"
" ```\n"
).
-spec key(binary()) -> key(any()).
key(Name) ->
{key, Name}.
-file("src/radiant.gleam", 146).
?DOC(" Set a custom fallback handler for unmatched requests.\n").
-spec fallback(
router(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
fallback(Router, Handler) ->
{router, erlang:element(2, Router), Handler, erlang:element(4, Router)}.
-file("src/radiant.gleam", 162).
?DOC(
" Add a middleware that wraps every request through this router.\n"
" Middlewares are applied in the order they are added (first added = outermost).\n"
"\n"
" ```gleam\n"
" radiant.new()\n"
" |> radiant.middleware(radiant.log(fn(msg) { io.println(msg) }))\n"
" |> radiant.middleware(radiant.cors(radiant.default_cors()))\n"
" |> radiant.get(\"/\", handler)\n"
" ```\n"
).
-spec middleware(
router(),
fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring())))
) -> router().
middleware(Router, Mw) ->
{router,
erlang:element(2, Router),
erlang:element(3, Router),
[Mw | erlang:element(4, Router)]}.
-file("src/radiant.gleam", 626).
?DOC(
" Mount a complete sub-router at a given path prefix.\n"
"\n"
" Unlike `scope`, which builds routes in the same context, `mount` allows\n"
" you to define independent routers (with their own middlewares) and\n"
" attach them to a parent router.\n"
"\n"
" Note: The sub-router's fallback handler is ignored. Unmatched requests\n"
" will fall through to the parent router's fallback.\n"
).
-spec mount(router(), binary(), router()) -> router().
mount(Router, Prefix, Sub_router) ->
Prefix_segs = radiant@internal@path:parse(Prefix),
Sub_routes = radiant@internal@tree:to_routes(erlang:element(2, Sub_router)),
gleam@list:fold(
Sub_routes,
Router,
fun(Acc_router, R) ->
{Method, Segments, Handler} = R,
With_middlewares = gleam@list:fold(
erlang:element(4, Sub_router),
Handler,
fun(H, Mw) -> Mw(H) end
),
Full_segments = lists:append(Prefix_segs, Segments),
New_tree = radiant@internal@tree:insert(
erlang:element(2, Acc_router),
Method,
Full_segments,
With_middlewares
),
{router,
New_tree,
erlang:element(3, Acc_router),
erlang:element(4, Acc_router)}
end
).
-file("src/radiant.gleam", 748).
-spec segments_to_pattern(list(radiant@internal@path:segment())) -> binary().
segments_to_pattern(Segments) ->
case Segments of
[] ->
<<"/"/utf8>>;
_ ->
<<"/"/utf8,
(begin
_pipe = gleam@list:map(Segments, fun(Seg) -> case Seg of
{literal, S} ->
S;
{capture, Name, int_t} ->
<<<<"<"/utf8, Name/binary>>/binary,
":int>"/utf8>>;
{capture, Name@1, string_t} ->
<<<<"<"/utf8, Name@1/binary>>/binary,
":string>"/utf8>>;
{wildcard, Name@2} ->
<<"*"/utf8, Name@2/binary>>
end end),
gleam@string:join(_pipe, <<"/"/utf8>>)
end)/binary>>
end.
-file("src/radiant.gleam", 740).
?DOC(
" Return all registered routes as `(method, pattern)` pairs.\n"
"\n"
" Useful for logging the route table at startup, contract tests,\n"
" or building documentation from a live router.\n"
"\n"
" ```gleam\n"
" radiant.routes(router)\n"
" // → [#(http.Get, \"/\"), #(http.Get, \"/users/<id:int>\"), ...]\n"
" ```\n"
).
-spec routes(router()) -> list({gleam@http:method(), binary()}).
routes(Router) ->
_pipe = radiant@internal@tree:to_routes(erlang:element(2, Router)),
gleam@list:map(
_pipe,
fun(R) ->
{Method, Segments, _} = R,
{Method, segments_to_pattern(Segments)}
end
).
-file("src/radiant.gleam", 779).
?DOC(
" Build a URL path from a route pattern and a list of `(name, value)` pairs.\n"
"\n"
" Returns `Error(Nil)` if any named parameter is missing from the list.\n"
" Extra keys in the list are silently ignored.\n"
"\n"
" ```gleam\n"
" radiant.path_for(\"/users/<id:int>/posts/<pid:int>\", [\n"
" #(\"id\", \"42\"), #(\"pid\", \"7\"),\n"
" ])\n"
" // → Ok(\"/users/42/posts/7\")\n"
"\n"
" radiant.path_for(\"/users/<id:int>\", [])\n"
" // → Error(Nil)\n"
" ```\n"
).
-spec path_for(binary(), list({binary(), binary()})) -> {ok, binary()} |
{error, nil}.
path_for(Pattern, Params) ->
Segments = radiant@internal@path:parse(Pattern),
Lookup = maps:from_list(Params),
gleam@result:'try'(gleam@list:try_map(Segments, fun(Seg) -> case Seg of
{literal, S} ->
{ok, S};
{capture, Name, _} ->
gleam_stdlib:map_get(Lookup, Name);
{wildcard, Name@1} ->
gleam_stdlib:map_get(Lookup, Name@1)
end end), fun(Parts) -> case Parts of
[] ->
{ok, <<"/"/utf8>>};
_ ->
{ok,
<<"/"/utf8,
(gleam@string:join(Parts, <<"/"/utf8>>))/binary>>}
end end).
-file("src/radiant.gleam", 816).
?DOC(
" Build a URL path using typed `Param` objects — more refactor-safe than `path_for`.\n"
"\n"
" Because you pass the same `Param` constant used for route registration,\n"
" renaming a capture in the pattern and updating the `Param` name is enough:\n"
" `validate_param` will catch any remaining mismatch at startup.\n"
"\n"
" ```gleam\n"
" pub const user_id = radiant.int(\"id\")\n"
"\n"
" // Route registration\n"
" router |> radiant.get1(\"/users/<id:int>\", user_id, handler)\n"
"\n"
" // URL building — user_id.name is always in sync with the route\n"
" radiant.path_for1(\"/users/<id:int>\", user_id, 42)\n"
" // → Ok(\"/users/42\")\n"
" ```\n"
).
-spec path_for1(binary(), param(PNH), PNH) -> {ok, binary()} | {error, nil}.
path_for1(Pattern, P1, V1) ->
path_for(Pattern, [{erlang:element(2, P1), (erlang:element(5, P1))(V1)}]).
-file("src/radiant.gleam", 821).
?DOC(" Build a URL path with two typed parameters.\n").
-spec path_for2(binary(), param(PNL), PNL, param(PNN), PNN) -> {ok, binary()} |
{error, nil}.
path_for2(Pattern, P1, V1, P2, V2) ->
path_for(
Pattern,
[{erlang:element(2, P1), (erlang:element(5, P1))(V1)},
{erlang:element(2, P2), (erlang:element(5, P2))(V2)}]
).
-file("src/radiant.gleam", 832).
?DOC(" Build a URL path with three typed parameters.\n").
-spec path_for3(binary(), param(PNR), PNR, param(PNT), PNT, param(PNV), PNV) -> {ok,
binary()} |
{error, nil}.
path_for3(Pattern, P1, V1, P2, V2, P3, V3) ->
path_for(
Pattern,
[{erlang:element(2, P1), (erlang:element(5, P1))(V1)},
{erlang:element(2, P2), (erlang:element(5, P2))(V2)},
{erlang:element(2, P3), (erlang:element(5, P3))(V3)}]
).
-file("src/radiant.gleam", 849).
?DOC(" Build a URL path with four typed parameters.\n").
-spec path_for4(
binary(),
param(PNZ),
PNZ,
param(POB),
POB,
param(POD),
POD,
param(POF),
POF
) -> {ok, binary()} | {error, nil}.
path_for4(Pattern, P1, V1, P2, V2, P3, V3, P4, V4) ->
path_for(
Pattern,
[{erlang:element(2, P1), (erlang:element(5, P1))(V1)},
{erlang:element(2, P2), (erlang:element(5, P2))(V2)},
{erlang:element(2, P3), (erlang:element(5, P3))(V3)},
{erlang:element(2, P4), (erlang:element(5, P4))(V4)}]
).
-file("src/radiant.gleam", 869).
?DOC(" Build a URL path with five typed parameters.\n").
-spec path_for5(
binary(),
param(POJ),
POJ,
param(POL),
POL,
param(PON),
PON,
param(POP),
POP,
param(POR),
POR
) -> {ok, binary()} | {error, nil}.
path_for5(Pattern, P1, V1, P2, V2, P3, V3, P4, V4, P5, V5) ->
path_for(
Pattern,
[{erlang:element(2, P1), (erlang:element(5, P1))(V1)},
{erlang:element(2, P2), (erlang:element(5, P2))(V2)},
{erlang:element(2, P3), (erlang:element(5, P3))(V3)},
{erlang:element(2, P4), (erlang:element(5, P4))(V4)},
{erlang:element(2, P5), (erlang:element(5, P5))(V5)}]
).
-file("src/radiant.gleam", 892).
?DOC(" Build a URL path with six typed parameters.\n").
-spec path_for6(
binary(),
param(POV),
POV,
param(POX),
POX,
param(POZ),
POZ,
param(PPB),
PPB,
param(PPD),
PPD,
param(PPF),
PPF
) -> {ok, binary()} | {error, nil}.
path_for6(Pattern, P1, V1, P2, V2, P3, V3, P4, V4, P5, V5, P6, V6) ->
path_for(
Pattern,
[{erlang:element(2, P1), (erlang:element(5, P1))(V1)},
{erlang:element(2, P2), (erlang:element(5, P2))(V2)},
{erlang:element(2, P3), (erlang:element(5, P3))(V3)},
{erlang:element(2, P4), (erlang:element(5, P4))(V4)},
{erlang:element(2, P5), (erlang:element(5, P5))(V5)},
{erlang:element(2, P6), (erlang:element(5, P6))(V6)}]
).
-file("src/radiant.gleam", 926).
-spec add_route_raw(
router(),
gleam@http:method(),
list(radiant@internal@path:segment()),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
add_route_raw(Router, Method, Segments, Handler) ->
_ = case radiant@internal@tree:check_capture_ambiguity(
erlang:element(2, Router),
Segments
) of
{ok, Existing} ->
Pattern = segments_to_pattern(Segments),
erlang:error(#{gleam_error => panic,
message => (<<<<<<<<<<"Radiant: Ambiguous capture in '"/utf8,
Pattern/binary>>/binary,
"'. A capture named '"/utf8>>/binary,
Existing/binary>>/binary,
"' of the same type already exists at the same path depth. "/utf8>>/binary,
"Routing between them is order-dependent. Use distinct types or restructure your routes."/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"add_route_raw"/utf8>>,
line => 935});
{error, _} ->
nil
end,
case radiant@internal@tree:get_handler(
erlang:element(2, Router),
Segments,
Method
) of
{ok, _} ->
Router;
{error, _} ->
{router,
radiant@internal@tree:insert(
erlang:element(2, Router),
Method,
Segments,
Handler
),
erlang:element(3, Router),
erlang:element(4, Router)}
end.
-file("src/radiant.gleam", 917).
-spec add_route(
router(),
gleam@http:method(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
add_route(Router, Method, Pattern, Handler) ->
add_route_raw(Router, Method, radiant@internal@path:parse(Pattern), Handler).
-file("src/radiant.gleam", 167).
?DOC(" Register a GET route.\n").
-spec get(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
get(Router, Pattern, Handler) ->
add_route(Router, get, Pattern, Handler).
-file("src/radiant.gleam", 176).
?DOC(" Register a POST route.\n").
-spec post(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
post(Router, Pattern, Handler) ->
add_route(Router, post, Pattern, Handler).
-file("src/radiant.gleam", 185).
?DOC(" Register a PUT route.\n").
-spec put(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
put(Router, Pattern, Handler) ->
add_route(Router, put, Pattern, Handler).
-file("src/radiant.gleam", 194).
?DOC(" Register a PATCH route.\n").
-spec patch(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
patch(Router, Pattern, Handler) ->
add_route(Router, patch, Pattern, Handler).
-file("src/radiant.gleam", 203).
?DOC(" Register a DELETE route.\n").
-spec delete(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
delete(Router, Pattern, Handler) ->
add_route(Router, delete, Pattern, Handler).
-file("src/radiant.gleam", 213).
?DOC(
" Register an OPTIONS route.\n"
" Useful for custom preflight handling when the `cors` middleware is not used.\n"
).
-spec options(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
options(Router, Pattern, Handler) ->
add_route(Router, options, Pattern, Handler).
-file("src/radiant.gleam", 722).
?DOC(
" Register the same handler for all standard HTTP methods on a pattern.\n"
" Useful for health check endpoints or method-agnostic catch-alls.\n"
"\n"
" ```gleam\n"
" radiant.new()\n"
" |> radiant.any(\"/health\", fn(_req) { radiant.ok(\"ok\") })\n"
" ```\n"
).
-spec any(
router(),
binary(),
fun((req()) -> gleam@http@response:response(bitstring()))
) -> router().
any(Router, Pattern, Handler) ->
_pipe = [get, post, put, patch, delete],
gleam@list:fold(
_pipe,
Router,
fun(R, M) -> add_route(R, M, Pattern, Handler) end
).
-file("src/radiant.gleam", 958).
-spec validate_param(
param(any()),
list(radiant@internal@path:segment()),
binary()
) -> nil.
validate_param(P, Segments, Pattern) ->
case gleam@list:any(Segments, fun(Seg) -> case Seg of
{capture, Name, _} ->
Name =:= erlang:element(2, P);
{wildcard, Name@1} ->
Name@1 =:= erlang:element(2, P);
_ ->
false
end end) of
true ->
nil;
false ->
erlang:error(#{gleam_error => panic,
message => (<<<<<<<<"Radiant: param '"/utf8,
(erlang:element(2, P))/binary>>/binary,
"' not found in pattern '"/utf8>>/binary,
Pattern/binary>>/binary,
"'. The Param name must match a capture in the route pattern."/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"validate_param"/utf8>>,
line => 974})
end.
-file("src/radiant.gleam", 985).
-spec apply_param_type(list(radiant@internal@path:segment()), param(any())) -> list(radiant@internal@path:segment()).
apply_param_type(Segments, P) ->
gleam@list:map(Segments, fun(Seg) -> case Seg of
{capture, Name, _} when Name =:= erlang:element(2, P) ->
{capture, Name, erlang:element(4, P)};
_ ->
Seg
end end).
-file("src/radiant.gleam", 997).
-spec typed1(
router(),
gleam@http:method(),
binary(),
param(PPT),
fun((req(), PPT) -> gleam@http@response:response(bitstring()))
) -> router().
typed1(Router, Method, Pattern, P1, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
Segments = apply_param_type(Raw, P1),
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed1"/utf8>>,
line => 1008,
value => _assert_fail,
start => 25752,
'end' => 25825,
pattern_start => 25763,
pattern_end => 25769})
end,
Handler(Req, V1@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 233).
?DOC(
" Register a GET route with one typed path parameter.\n"
" The handler receives the extracted value directly — no manual extraction.\n"
"\n"
" ```gleam\n"
" router |> radiant.get1(\"/users/:id\", radiant.int(\"id\"), fn(req, id) {\n"
" radiant.ok(\"User \" <> int.to_string(id))\n"
" })\n"
" ```\n"
).
-spec get1(
router(),
binary(),
param(PDQ),
fun((req(), PDQ) -> gleam@http@response:response(bitstring()))
) -> router().
get1(Router, Pattern, P1, Handler) ->
typed1(Router, get, Pattern, P1, Handler).
-file("src/radiant.gleam", 242).
-spec post1(
router(),
binary(),
param(PDT),
fun((req(), PDT) -> gleam@http@response:response(bitstring()))
) -> router().
post1(Router, Pattern, P1, Handler) ->
typed1(Router, post, Pattern, P1, Handler).
-file("src/radiant.gleam", 251).
-spec put1(
router(),
binary(),
param(PDW),
fun((req(), PDW) -> gleam@http@response:response(bitstring()))
) -> router().
put1(Router, Pattern, P1, Handler) ->
typed1(Router, put, Pattern, P1, Handler).
-file("src/radiant.gleam", 260).
-spec patch1(
router(),
binary(),
param(PDZ),
fun((req(), PDZ) -> gleam@http@response:response(bitstring()))
) -> router().
patch1(Router, Pattern, P1, Handler) ->
typed1(Router, patch, Pattern, P1, Handler).
-file("src/radiant.gleam", 269).
-spec delete1(
router(),
binary(),
param(PEC),
fun((req(), PEC) -> gleam@http@response:response(bitstring()))
) -> router().
delete1(Router, Pattern, P1, Handler) ->
typed1(Router, delete, Pattern, P1, Handler).
-file("src/radiant.gleam", 1014).
-spec typed2(
router(),
gleam@http:method(),
binary(),
param(PPW),
param(PPY),
fun((req(), PPW, PPY) -> gleam@http@response:response(bitstring()))
) -> router().
typed2(Router, Method, Pattern, P1, P2, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
validate_param(P2, Raw, Pattern),
Segments = begin
_pipe = Raw,
_pipe@1 = apply_param_type(_pipe, P1),
apply_param_type(_pipe@1, P2)
end,
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe@2 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe@2, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed2"/utf8>>,
line => 1027,
value => _assert_fail,
start => 26294,
'end' => 26367,
pattern_start => 26305,
pattern_end => 26311})
end,
V2@1 = case begin
_pipe@3 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P2)
),
gleam@result:'try'(_pipe@3, erlang:element(3, P2))
end of
{ok, V2} -> V2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed2"/utf8>>,
line => 1028,
value => _assert_fail@1,
start => 26372,
'end' => 26445,
pattern_start => 26383,
pattern_end => 26389})
end,
Handler(Req, V1@1, V2@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 287).
?DOC(
" Register a GET route with two typed path parameters.\n"
"\n"
" ```gleam\n"
" router |> radiant.get2(\n"
" \"/users/:uid/posts/:pid\",\n"
" radiant.int(\"uid\"), radiant.int(\"pid\"),\n"
" fn(req, uid, pid) { radiant.ok(int.to_string(uid) <> \"/\" <> int.to_string(pid)) },\n"
" )\n"
" ```\n"
).
-spec get2(
router(),
binary(),
param(PEF),
param(PEH),
fun((req(), PEF, PEH) -> gleam@http@response:response(bitstring()))
) -> router().
get2(Router, Pattern, P1, P2, Handler) ->
typed2(Router, get, Pattern, P1, P2, Handler).
-file("src/radiant.gleam", 297).
-spec post2(
router(),
binary(),
param(PEK),
param(PEM),
fun((req(), PEK, PEM) -> gleam@http@response:response(bitstring()))
) -> router().
post2(Router, Pattern, P1, P2, Handler) ->
typed2(Router, post, Pattern, P1, P2, Handler).
-file("src/radiant.gleam", 307).
-spec put2(
router(),
binary(),
param(PEP),
param(PER),
fun((req(), PEP, PER) -> gleam@http@response:response(bitstring()))
) -> router().
put2(Router, Pattern, P1, P2, Handler) ->
typed2(Router, put, Pattern, P1, P2, Handler).
-file("src/radiant.gleam", 317).
-spec patch2(
router(),
binary(),
param(PEU),
param(PEW),
fun((req(), PEU, PEW) -> gleam@http@response:response(bitstring()))
) -> router().
patch2(Router, Pattern, P1, P2, Handler) ->
typed2(Router, patch, Pattern, P1, P2, Handler).
-file("src/radiant.gleam", 327).
-spec delete2(
router(),
binary(),
param(PEZ),
param(PFB),
fun((req(), PEZ, PFB) -> gleam@http@response:response(bitstring()))
) -> router().
delete2(Router, Pattern, P1, P2, Handler) ->
typed2(Router, delete, Pattern, P1, P2, Handler).
-file("src/radiant.gleam", 1034).
-spec typed3(
router(),
gleam@http:method(),
binary(),
param(PQB),
param(PQD),
param(PQF),
fun((req(), PQB, PQD, PQF) -> gleam@http@response:response(bitstring()))
) -> router().
typed3(Router, Method, Pattern, P1, P2, P3, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
validate_param(P2, Raw, Pattern),
validate_param(P3, Raw, Pattern),
Segments = begin
_pipe = Raw,
_pipe@1 = apply_param_type(_pipe, P1),
_pipe@2 = apply_param_type(_pipe@1, P2),
apply_param_type(_pipe@2, P3)
end,
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe@3 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe@3, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed3"/utf8>>,
line => 1050,
value => _assert_fail,
start => 27000,
'end' => 27073,
pattern_start => 27011,
pattern_end => 27017})
end,
V2@1 = case begin
_pipe@4 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P2)
),
gleam@result:'try'(_pipe@4, erlang:element(3, P2))
end of
{ok, V2} -> V2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed3"/utf8>>,
line => 1051,
value => _assert_fail@1,
start => 27078,
'end' => 27151,
pattern_start => 27089,
pattern_end => 27095})
end,
V3@1 = case begin
_pipe@5 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P3)
),
gleam@result:'try'(_pipe@5, erlang:element(3, P3))
end of
{ok, V3} -> V3;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed3"/utf8>>,
line => 1052,
value => _assert_fail@2,
start => 27156,
'end' => 27229,
pattern_start => 27167,
pattern_end => 27173})
end,
Handler(Req, V1@1, V2@1, V3@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 338).
?DOC(" Register a GET route with three typed path parameters.\n").
-spec get3(
router(),
binary(),
param(PFE),
param(PFG),
param(PFI),
fun((req(), PFE, PFG, PFI) -> gleam@http@response:response(bitstring()))
) -> router().
get3(Router, Pattern, P1, P2, P3, Handler) ->
typed3(Router, get, Pattern, P1, P2, P3, Handler).
-file("src/radiant.gleam", 349).
-spec post3(
router(),
binary(),
param(PFL),
param(PFN),
param(PFP),
fun((req(), PFL, PFN, PFP) -> gleam@http@response:response(bitstring()))
) -> router().
post3(Router, Pattern, P1, P2, P3, Handler) ->
typed3(Router, post, Pattern, P1, P2, P3, Handler).
-file("src/radiant.gleam", 360).
-spec put3(
router(),
binary(),
param(PFS),
param(PFU),
param(PFW),
fun((req(), PFS, PFU, PFW) -> gleam@http@response:response(bitstring()))
) -> router().
put3(Router, Pattern, P1, P2, P3, Handler) ->
typed3(Router, put, Pattern, P1, P2, P3, Handler).
-file("src/radiant.gleam", 371).
-spec patch3(
router(),
binary(),
param(PFZ),
param(PGB),
param(PGD),
fun((req(), PFZ, PGB, PGD) -> gleam@http@response:response(bitstring()))
) -> router().
patch3(Router, Pattern, P1, P2, P3, Handler) ->
typed3(Router, patch, Pattern, P1, P2, P3, Handler).
-file("src/radiant.gleam", 382).
-spec delete3(
router(),
binary(),
param(PGG),
param(PGI),
param(PGK),
fun((req(), PGG, PGI, PGK) -> gleam@http@response:response(bitstring()))
) -> router().
delete3(Router, Pattern, P1, P2, P3, Handler) ->
typed3(Router, delete, Pattern, P1, P2, P3, Handler).
-file("src/radiant.gleam", 1058).
-spec typed4(
router(),
gleam@http:method(),
binary(),
param(PQI),
param(PQK),
param(PQM),
param(PQO),
fun((req(), PQI, PQK, PQM, PQO) -> gleam@http@response:response(bitstring()))
) -> router().
typed4(Router, Method, Pattern, P1, P2, P3, P4, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
validate_param(P2, Raw, Pattern),
validate_param(P3, Raw, Pattern),
validate_param(P4, Raw, Pattern),
Segments = begin
_pipe = Raw,
_pipe@1 = apply_param_type(_pipe, P1),
_pipe@2 = apply_param_type(_pipe@1, P2),
_pipe@3 = apply_param_type(_pipe@2, P3),
apply_param_type(_pipe@3, P4)
end,
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe@4 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe@4, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed4"/utf8>>,
line => 1080,
value => _assert_fail,
start => 27882,
'end' => 27955,
pattern_start => 27893,
pattern_end => 27899})
end,
V2@1 = case begin
_pipe@5 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P2)
),
gleam@result:'try'(_pipe@5, erlang:element(3, P2))
end of
{ok, V2} -> V2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed4"/utf8>>,
line => 1081,
value => _assert_fail@1,
start => 27960,
'end' => 28033,
pattern_start => 27971,
pattern_end => 27977})
end,
V3@1 = case begin
_pipe@6 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P3)
),
gleam@result:'try'(_pipe@6, erlang:element(3, P3))
end of
{ok, V3} -> V3;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed4"/utf8>>,
line => 1082,
value => _assert_fail@2,
start => 28038,
'end' => 28111,
pattern_start => 28049,
pattern_end => 28055})
end,
V4@1 = case begin
_pipe@7 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P4)
),
gleam@result:'try'(_pipe@7, erlang:element(3, P4))
end of
{ok, V4} -> V4;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed4"/utf8>>,
line => 1083,
value => _assert_fail@3,
start => 28116,
'end' => 28189,
pattern_start => 28127,
pattern_end => 28133})
end,
Handler(Req, V1@1, V2@1, V3@1, V4@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 394).
?DOC(" Register a GET route with four typed path parameters.\n").
-spec get4(
router(),
binary(),
param(PGN),
param(PGP),
param(PGR),
param(PGT),
fun((req(), PGN, PGP, PGR, PGT) -> gleam@http@response:response(bitstring()))
) -> router().
get4(Router, Pattern, P1, P2, P3, P4, Handler) ->
typed4(Router, get, Pattern, P1, P2, P3, P4, Handler).
-file("src/radiant.gleam", 406).
-spec post4(
router(),
binary(),
param(PGW),
param(PGY),
param(PHA),
param(PHC),
fun((req(), PGW, PGY, PHA, PHC) -> gleam@http@response:response(bitstring()))
) -> router().
post4(Router, Pattern, P1, P2, P3, P4, Handler) ->
typed4(Router, post, Pattern, P1, P2, P3, P4, Handler).
-file("src/radiant.gleam", 418).
-spec put4(
router(),
binary(),
param(PHF),
param(PHH),
param(PHJ),
param(PHL),
fun((req(), PHF, PHH, PHJ, PHL) -> gleam@http@response:response(bitstring()))
) -> router().
put4(Router, Pattern, P1, P2, P3, P4, Handler) ->
typed4(Router, put, Pattern, P1, P2, P3, P4, Handler).
-file("src/radiant.gleam", 430).
-spec patch4(
router(),
binary(),
param(PHO),
param(PHQ),
param(PHS),
param(PHU),
fun((req(), PHO, PHQ, PHS, PHU) -> gleam@http@response:response(bitstring()))
) -> router().
patch4(Router, Pattern, P1, P2, P3, P4, Handler) ->
typed4(Router, patch, Pattern, P1, P2, P3, P4, Handler).
-file("src/radiant.gleam", 442).
-spec delete4(
router(),
binary(),
param(PHX),
param(PHZ),
param(PIB),
param(PID),
fun((req(), PHX, PHZ, PIB, PID) -> gleam@http@response:response(bitstring()))
) -> router().
delete4(Router, Pattern, P1, P2, P3, P4, Handler) ->
typed4(Router, delete, Pattern, P1, P2, P3, P4, Handler).
-file("src/radiant.gleam", 1089).
-spec typed5(
router(),
gleam@http:method(),
binary(),
param(PQR),
param(PQT),
param(PQV),
param(PQX),
param(PQZ),
fun((req(), PQR, PQT, PQV, PQX, PQZ) -> gleam@http@response:response(bitstring()))
) -> router().
typed5(Router, Method, Pattern, P1, P2, P3, P4, P5, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
validate_param(P2, Raw, Pattern),
validate_param(P3, Raw, Pattern),
validate_param(P4, Raw, Pattern),
validate_param(P5, Raw, Pattern),
Segments = begin
_pipe = Raw,
_pipe@1 = apply_param_type(_pipe, P1),
_pipe@2 = apply_param_type(_pipe@1, P2),
_pipe@3 = apply_param_type(_pipe@2, P3),
_pipe@4 = apply_param_type(_pipe@3, P4),
apply_param_type(_pipe@4, P5)
end,
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe@5 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe@5, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed5"/utf8>>,
line => 1114,
value => _assert_fail,
start => 28928,
'end' => 29001,
pattern_start => 28939,
pattern_end => 28945})
end,
V2@1 = case begin
_pipe@6 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P2)
),
gleam@result:'try'(_pipe@6, erlang:element(3, P2))
end of
{ok, V2} -> V2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed5"/utf8>>,
line => 1115,
value => _assert_fail@1,
start => 29006,
'end' => 29079,
pattern_start => 29017,
pattern_end => 29023})
end,
V3@1 = case begin
_pipe@7 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P3)
),
gleam@result:'try'(_pipe@7, erlang:element(3, P3))
end of
{ok, V3} -> V3;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed5"/utf8>>,
line => 1116,
value => _assert_fail@2,
start => 29084,
'end' => 29157,
pattern_start => 29095,
pattern_end => 29101})
end,
V4@1 = case begin
_pipe@8 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P4)
),
gleam@result:'try'(_pipe@8, erlang:element(3, P4))
end of
{ok, V4} -> V4;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed5"/utf8>>,
line => 1117,
value => _assert_fail@3,
start => 29162,
'end' => 29235,
pattern_start => 29173,
pattern_end => 29179})
end,
V5@1 = case begin
_pipe@9 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P5)
),
gleam@result:'try'(_pipe@9, erlang:element(3, P5))
end of
{ok, V5} -> V5;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed5"/utf8>>,
line => 1118,
value => _assert_fail@4,
start => 29240,
'end' => 29313,
pattern_start => 29251,
pattern_end => 29257})
end,
Handler(Req, V1@1, V2@1, V3@1, V4@1, V5@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 455).
?DOC(" Register a GET route with five typed path parameters.\n").
-spec get5(
router(),
binary(),
param(PIG),
param(PII),
param(PIK),
param(PIM),
param(PIO),
fun((req(), PIG, PII, PIK, PIM, PIO) -> gleam@http@response:response(bitstring()))
) -> router().
get5(Router, Pattern, P1, P2, P3, P4, P5, Handler) ->
typed5(Router, get, Pattern, P1, P2, P3, P4, P5, Handler).
-file("src/radiant.gleam", 468).
-spec post5(
router(),
binary(),
param(PIR),
param(PIT),
param(PIV),
param(PIX),
param(PIZ),
fun((req(), PIR, PIT, PIV, PIX, PIZ) -> gleam@http@response:response(bitstring()))
) -> router().
post5(Router, Pattern, P1, P2, P3, P4, P5, Handler) ->
typed5(Router, post, Pattern, P1, P2, P3, P4, P5, Handler).
-file("src/radiant.gleam", 481).
-spec put5(
router(),
binary(),
param(PJC),
param(PJE),
param(PJG),
param(PJI),
param(PJK),
fun((req(), PJC, PJE, PJG, PJI, PJK) -> gleam@http@response:response(bitstring()))
) -> router().
put5(Router, Pattern, P1, P2, P3, P4, P5, Handler) ->
typed5(Router, put, Pattern, P1, P2, P3, P4, P5, Handler).
-file("src/radiant.gleam", 494).
-spec patch5(
router(),
binary(),
param(PJN),
param(PJP),
param(PJR),
param(PJT),
param(PJV),
fun((req(), PJN, PJP, PJR, PJT, PJV) -> gleam@http@response:response(bitstring()))
) -> router().
patch5(Router, Pattern, P1, P2, P3, P4, P5, Handler) ->
typed5(Router, patch, Pattern, P1, P2, P3, P4, P5, Handler).
-file("src/radiant.gleam", 507).
-spec delete5(
router(),
binary(),
param(PJY),
param(PKA),
param(PKC),
param(PKE),
param(PKG),
fun((req(), PJY, PKA, PKC, PKE, PKG) -> gleam@http@response:response(bitstring()))
) -> router().
delete5(Router, Pattern, P1, P2, P3, P4, P5, Handler) ->
typed5(Router, delete, Pattern, P1, P2, P3, P4, P5, Handler).
-file("src/radiant.gleam", 1124).
-spec typed6(
router(),
gleam@http:method(),
binary(),
param(PRC),
param(PRE),
param(PRG),
param(PRI),
param(PRK),
param(PRM),
fun((req(), PRC, PRE, PRG, PRI, PRK, PRM) -> gleam@http@response:response(bitstring()))
) -> router().
typed6(Router, Method, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
Raw = radiant@internal@path:parse(Pattern),
validate_param(P1, Raw, Pattern),
validate_param(P2, Raw, Pattern),
validate_param(P3, Raw, Pattern),
validate_param(P4, Raw, Pattern),
validate_param(P5, Raw, Pattern),
validate_param(P6, Raw, Pattern),
Segments = begin
_pipe = Raw,
_pipe@1 = apply_param_type(_pipe, P1),
_pipe@2 = apply_param_type(_pipe@1, P2),
_pipe@3 = apply_param_type(_pipe@2, P3),
_pipe@4 = apply_param_type(_pipe@3, P4),
_pipe@5 = apply_param_type(_pipe@4, P5),
apply_param_type(_pipe@5, P6)
end,
Wrapped = fun(Req) ->
V1@1 = case begin
_pipe@6 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P1)
),
gleam@result:'try'(_pipe@6, erlang:element(3, P1))
end of
{ok, V1} -> V1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1152,
value => _assert_fail,
start => 30138,
'end' => 30211,
pattern_start => 30149,
pattern_end => 30155})
end,
V2@1 = case begin
_pipe@7 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P2)
),
gleam@result:'try'(_pipe@7, erlang:element(3, P2))
end of
{ok, V2} -> V2;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1153,
value => _assert_fail@1,
start => 30216,
'end' => 30289,
pattern_start => 30227,
pattern_end => 30233})
end,
V3@1 = case begin
_pipe@8 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P3)
),
gleam@result:'try'(_pipe@8, erlang:element(3, P3))
end of
{ok, V3} -> V3;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1154,
value => _assert_fail@2,
start => 30294,
'end' => 30367,
pattern_start => 30305,
pattern_end => 30311})
end,
V4@1 = case begin
_pipe@9 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P4)
),
gleam@result:'try'(_pipe@9, erlang:element(3, P4))
end of
{ok, V4} -> V4;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1155,
value => _assert_fail@3,
start => 30372,
'end' => 30445,
pattern_start => 30383,
pattern_end => 30389})
end,
V5@1 = case begin
_pipe@10 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P5)
),
gleam@result:'try'(_pipe@10, erlang:element(3, P5))
end of
{ok, V5} -> V5;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1156,
value => _assert_fail@4,
start => 30450,
'end' => 30523,
pattern_start => 30461,
pattern_end => 30467})
end,
V6@1 = case begin
_pipe@11 = gleam_stdlib:map_get(
erlang:element(3, Req),
erlang:element(2, P6)
),
gleam@result:'try'(_pipe@11, erlang:element(3, P6))
end of
{ok, V6} -> V6;
_assert_fail@5 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"typed6"/utf8>>,
line => 1157,
value => _assert_fail@5,
start => 30528,
'end' => 30601,
pattern_start => 30539,
pattern_end => 30545})
end,
Handler(Req, V1@1, V2@1, V3@1, V4@1, V5@1, V6@1)
end,
add_route_raw(Router, Method, Segments, Wrapped).
-file("src/radiant.gleam", 521).
?DOC(" Register a GET route with six typed path parameters.\n").
-spec get6(
router(),
binary(),
param(PKJ),
param(PKL),
param(PKN),
param(PKP),
param(PKR),
param(PKT),
fun((req(), PKJ, PKL, PKN, PKP, PKR, PKT) -> gleam@http@response:response(bitstring()))
) -> router().
get6(Router, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
typed6(Router, get, Pattern, P1, P2, P3, P4, P5, P6, Handler).
-file("src/radiant.gleam", 535).
-spec post6(
router(),
binary(),
param(PKW),
param(PKY),
param(PLA),
param(PLC),
param(PLE),
param(PLG),
fun((req(), PKW, PKY, PLA, PLC, PLE, PLG) -> gleam@http@response:response(bitstring()))
) -> router().
post6(Router, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
typed6(Router, post, Pattern, P1, P2, P3, P4, P5, P6, Handler).
-file("src/radiant.gleam", 549).
-spec put6(
router(),
binary(),
param(PLJ),
param(PLL),
param(PLN),
param(PLP),
param(PLR),
param(PLT),
fun((req(), PLJ, PLL, PLN, PLP, PLR, PLT) -> gleam@http@response:response(bitstring()))
) -> router().
put6(Router, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
typed6(Router, put, Pattern, P1, P2, P3, P4, P5, P6, Handler).
-file("src/radiant.gleam", 563).
-spec patch6(
router(),
binary(),
param(PLW),
param(PLY),
param(PMA),
param(PMC),
param(PME),
param(PMG),
fun((req(), PLW, PLY, PMA, PMC, PME, PMG) -> gleam@http@response:response(bitstring()))
) -> router().
patch6(Router, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
typed6(Router, patch, Pattern, P1, P2, P3, P4, P5, P6, Handler).
-file("src/radiant.gleam", 577).
-spec delete6(
router(),
binary(),
param(PMJ),
param(PML),
param(PMN),
param(PMP),
param(PMR),
param(PMT),
fun((req(), PMJ, PML, PMN, PMP, PMR, PMT) -> gleam@http@response:response(bitstring()))
) -> router().
delete6(Router, Pattern, P1, P2, P3, P4, P5, P6, Handler) ->
typed6(Router, delete, Pattern, P1, P2, P3, P4, P5, P6, Handler).
-file("src/radiant.gleam", 1168).
?DOC(" The request HTTP method.\n").
-spec method(req()) -> gleam@http:method().
method(Req) ->
erlang:element(2, erlang:element(2, Req)).
-file("src/radiant.gleam", 1173).
?DOC(" The request path (e.g. \"/users/42\").\n").
-spec req_path(req()) -> binary().
req_path(Req) ->
erlang:element(8, erlang:element(2, Req)).
-file("src/radiant.gleam", 1178).
?DOC(" Get a request header by key (case-insensitive).\n").
-spec header(req(), binary()) -> {ok, binary()} | {error, nil}.
header(Req, Key) ->
gleam@http@request:get_header(erlang:element(2, Req), Key).
-file("src/radiant.gleam", 1183).
?DOC(" All request headers.\n").
-spec headers(req()) -> list({binary(), binary()}).
headers(Req) ->
erlang:element(3, erlang:element(2, Req)).
-file("src/radiant.gleam", 1188).
?DOC(" The raw request body as BitArray.\n").
-spec body(req()) -> bitstring().
body(Req) ->
erlang:element(4, erlang:element(2, Req)).
-file("src/radiant.gleam", 1193).
?DOC(" The request body decoded as UTF-8 text.\n").
-spec text_body(req()) -> {ok, binary()} | {error, nil}.
text_body(Req) ->
gleam@bit_array:to_string(erlang:element(4, erlang:element(2, Req))).
-file("src/radiant.gleam", 1203).
?DOC(
" Extract a path parameter as String.\n"
"\n"
" ```gleam\n"
" // pattern: \"/users/:name\"\n"
" radiant.str_param(req, \"name\") // Ok(\"alice\")\n"
" ```\n"
).
-spec str_param(req(), binary()) -> {ok, binary()} | {error, nil}.
str_param(Req, Name) ->
gleam_stdlib:map_get(erlang:element(3, Req), Name).
-file("src/radiant.gleam", 1213).
?DOC(
" Extract a path parameter and parse it as Int.\n"
"\n"
" ```gleam\n"
" // pattern: \"/users/:id\"\n"
" radiant.int_param(req, \"id\") // Ok(42)\n"
" ```\n"
).
-spec int_param(req(), binary()) -> {ok, integer()} | {error, nil}.
int_param(Req, Name) ->
_pipe = gleam_stdlib:map_get(erlang:element(3, Req), Name),
gleam@result:'try'(_pipe, fun gleam_stdlib:parse_int/1).
-file("src/radiant.gleam", 1225).
?DOC(" All query parameters as key-value pairs.\n").
-spec queries(req()) -> list({binary(), binary()}).
queries(Req) ->
case erlang:element(9, erlang:element(2, Req)) of
{some, Q} ->
case gleam_stdlib:parse_query(Q) of
{ok, Pairs} ->
Pairs;
{error, nil} ->
[]
end;
none ->
[]
end.
-file("src/radiant.gleam", 1219).
?DOC(" Get a single query parameter by key.\n").
-spec 'query'(req(), binary()) -> {ok, binary()} | {error, nil}.
'query'(Req, Key) ->
_pipe = queries(Req),
gleam@list:key_find(_pipe, Key).
-file("src/radiant.gleam", 1237).
?DOC(" Get a query parameter parsed as Int.\n").
-spec query_int(req(), binary()) -> {ok, integer()} | {error, nil}.
query_int(Req, Key) ->
_pipe = 'query'(Req, Key),
gleam@result:'try'(_pipe, fun gleam_stdlib:parse_int/1).
-file("src/radiant.gleam", 1242).
?DOC(" Get a query parameter parsed as Float.\n").
-spec query_float(req(), binary()) -> {ok, float()} | {error, nil}.
query_float(Req, Key) ->
_pipe = 'query'(Req, Key),
gleam@result:'try'(_pipe, fun gleam_stdlib:parse_float/1).
-file("src/radiant.gleam", 1248).
?DOC(
" Get a query parameter parsed as Bool.\n"
" Accepts `\"true\"`/`\"1\"` → `True`, `\"false\"`/`\"0\"` → `False`. Anything else returns `Error(Nil)`.\n"
).
-spec query_bool(req(), binary()) -> {ok, boolean()} | {error, nil}.
query_bool(Req, Key) ->
case 'query'(Req, Key) of
{ok, <<"true"/utf8>>} ->
{ok, true};
{ok, <<"1"/utf8>>} ->
{ok, true};
{ok, <<"false"/utf8>>} ->
{ok, false};
{ok, <<"0"/utf8>>} ->
{ok, false};
_ ->
{error, nil}
end.
-file("src/radiant.gleam", 1257).
?DOC(" Access the underlying `Request(BitArray)` for anything radiant doesn't wrap.\n").
-spec original(req()) -> gleam@http@request:request(bitstring()).
original(Req) ->
erlang:element(2, Req).
-file("src/radiant.gleam", 1269).
?DOC(
" Store a typed value in the request context.\n"
" Use a `Key(a)` constant to guarantee type-safe retrieval.\n"
"\n"
" ```gleam\n"
" pub const user_key: radiant.Key(User) = radiant.key(\"user\")\n"
"\n"
" radiant.set_context(req, user_key, User(name: \"Alice\"))\n"
" ```\n"
).
-spec set_context(req(), key(PSI), PSI) -> req().
set_context(Req, K, Value) ->
{key, Name} = K,
{req,
erlang:element(2, Req),
erlang:element(3, Req),
gleam@dict:insert(
erlang:element(4, Req),
Name,
gleam_stdlib:identity(Value)
)}.
-file("src/radiant.gleam", 1280).
?DOC(
" Retrieve a typed value from the request context.\n"
" Returns `Ok(a)` if the key was set, `Error(Nil)` otherwise.\n"
"\n"
" ```gleam\n"
" let assert Ok(user) = radiant.get_context(req, user_key)\n"
" ```\n"
).
-spec get_context(req(), key(PSK)) -> {ok, PSK} | {error, nil}.
get_context(Req, K) ->
{key, Name} = K,
case gleam_stdlib:map_get(erlang:element(4, Req), Name) of
{ok, Dyn} ->
{ok, gleam_stdlib:identity(Dyn)};
{error, _} ->
{error, nil}
end.
-file("src/radiant.gleam", 1299).
?DOC(" Build a response with the given status and UTF-8 text body.\n").
-spec response(integer(), binary()) -> gleam@http@response:response(bitstring()).
response(Status, Body_text) ->
{response, Status, [], <<Body_text/binary>>}.
-file("src/radiant.gleam", 1304).
?DOC(" 200 OK with text body.\n").
-spec ok(binary()) -> gleam@http@response:response(bitstring()).
ok(Body_text) ->
response(200, Body_text).
-file("src/radiant.gleam", 1309).
?DOC(" 201 Created with text body.\n").
-spec created(binary()) -> gleam@http@response:response(bitstring()).
created(Body_text) ->
response(201, Body_text).
-file("src/radiant.gleam", 1314).
?DOC(" 204 No Content (empty body).\n").
-spec no_content() -> gleam@http@response:response(bitstring()).
no_content() ->
response(204, <<""/utf8>>).
-file("src/radiant.gleam", 1319).
?DOC(" 404 Not Found (empty body).\n").
-spec not_found() -> gleam@http@response:response(bitstring()).
not_found() ->
response(404, <<""/utf8>>).
-file("src/radiant.gleam", 141).
?DOC(" Create an empty router with a default 404 fallback.\n").
-spec new() -> router().
new() ->
{router, radiant@internal@tree:new(), fun(_) -> not_found() end, []}.
-file("src/radiant.gleam", 601).
?DOC(
" Group routes under a common path prefix.\n"
"\n"
" ```gleam\n"
" radiant.new()\n"
" |> radiant.scope(\"/api/v1\", fn(r) {\n"
" r\n"
" |> radiant.get(\"/users\", list_users)\n"
" |> radiant.get(\"/users/:id\", show_user)\n"
" })\n"
" ```\n"
).
-spec scope(router(), binary(), fun((router()) -> router())) -> router().
scope(Router, Prefix, Builder) ->
Scoped = Builder(new()),
Prefix_segs = radiant@internal@path:parse(Prefix),
Sub_routes = radiant@internal@tree:to_routes(erlang:element(2, Scoped)),
gleam@list:fold(
Sub_routes,
Router,
fun(Acc_router, R) ->
{Method, Segments, Handler} = R,
Full_segments = lists:append(Prefix_segs, Segments),
New_tree = radiant@internal@tree:insert(
erlang:element(2, Acc_router),
Method,
Full_segments,
Handler
),
{router,
New_tree,
erlang:element(3, Acc_router),
erlang:element(4, Acc_router)}
end
).
-file("src/radiant.gleam", 1324).
?DOC(" 400 Bad Request (empty body).\n").
-spec bad_request() -> gleam@http@response:response(bitstring()).
bad_request() ->
response(400, <<""/utf8>>).
-file("src/radiant.gleam", 1330).
?DOC(
" 401 Unauthorized (empty body).\n"
" Set `www-authenticate` with `with_header` if needed.\n"
).
-spec unauthorized() -> gleam@http@response:response(bitstring()).
unauthorized() ->
response(401, <<""/utf8>>).
-file("src/radiant.gleam", 1335).
?DOC(" 403 Forbidden (empty body).\n").
-spec forbidden() -> gleam@http@response:response(bitstring()).
forbidden() ->
response(403, <<""/utf8>>).
-file("src/radiant.gleam", 1347).
?DOC(
" 422 Unprocessable Entity (empty body).\n"
" Standard response for semantic validation failures (e.g. invalid field values).\n"
).
-spec unprocessable_entity() -> gleam@http@response:response(bitstring()).
unprocessable_entity() ->
response(422, <<""/utf8>>).
-file("src/radiant.gleam", 1352).
?DOC(" 500 Internal Server Error (empty body).\n").
-spec internal_server_error() -> gleam@http@response:response(bitstring()).
internal_server_error() ->
response(500, <<""/utf8>>).
-file("src/radiant.gleam", 1357).
?DOC(" 400 Bad Request with a text body.\n").
-spec bad_request_with(binary()) -> gleam@http@response:response(bitstring()).
bad_request_with(Body_text) ->
response(400, Body_text).
-file("src/radiant.gleam", 1362).
?DOC(" 401 Unauthorized with a text body.\n").
-spec unauthorized_with(binary()) -> gleam@http@response:response(bitstring()).
unauthorized_with(Body_text) ->
response(401, Body_text).
-file("src/radiant.gleam", 1367).
?DOC(" 403 Forbidden with a text body.\n").
-spec forbidden_with(binary()) -> gleam@http@response:response(bitstring()).
forbidden_with(Body_text) ->
response(403, Body_text).
-file("src/radiant.gleam", 1372).
?DOC(" 404 Not Found with a text body.\n").
-spec not_found_with(binary()) -> gleam@http@response:response(bitstring()).
not_found_with(Body_text) ->
response(404, Body_text).
-file("src/radiant.gleam", 1377).
?DOC(" 422 Unprocessable Entity with a text body.\n").
-spec unprocessable_entity_with(binary()) -> gleam@http@response:response(bitstring()).
unprocessable_entity_with(Body_text) ->
response(422, Body_text).
-file("src/radiant.gleam", 1382).
?DOC(" 500 Internal Server Error with a text body.\n").
-spec internal_server_error_with(binary()) -> gleam@http@response:response(bitstring()).
internal_server_error_with(Body_text) ->
response(500, Body_text).
-file("src/radiant.gleam", 1399).
?DOC(" 303 See Other redirect.\n").
-spec redirect(binary()) -> gleam@http@response:response(bitstring()).
redirect(Uri) ->
{response, 303, [{<<"location"/utf8>>, Uri}], <<>>}.
-file("src/radiant.gleam", 1416).
?DOC(" Set a header on a response (key is lowercased automatically).\n").
-spec with_header(gleam@http@response:response(bitstring()), binary(), binary()) -> gleam@http@response:response(bitstring()).
with_header(Resp, Key, Value) ->
gleam@http@response:set_header(Resp, Key, Value).
-file("src/radiant.gleam", 1340).
?DOC(" 405 Method Not Allowed with an `allow` header.\n").
-spec method_not_allowed(binary()) -> gleam@http@response:response(bitstring()).
method_not_allowed(Allowed) ->
_pipe = response(405, <<""/utf8>>),
with_header(_pipe, <<"allow"/utf8>>, Allowed).
-file("src/radiant.gleam", 651).
?DOC(
" Dispatch a raw HTTP request through the router, returning a response.\n"
"\n"
" This is the main entry point connecting radiant to any HTTP server.\n"
" Middlewares are applied in registration order (first added = outermost).\n"
"\n"
" If the path matches a route but the method does not, returns 405 Method\n"
" Not Allowed with an `allow` header listing the accepted methods.\n"
).
-spec handle(router(), gleam@http@request:request(bitstring())) -> gleam@http@response:response(bitstring()).
handle(Router, Req) ->
Dispatch = fun(R) ->
Segments = radiant@internal@path:split(
erlang:element(8, erlang:element(2, R))
),
case radiant@internal@tree:match(
erlang:element(2, Router),
erlang:element(2, erlang:element(2, R)),
Segments
) of
{ok, {Handler, Params}} ->
Handler(
{req, erlang:element(2, R), Params, erlang:element(4, R)}
);
{error, nil} ->
Head_result = case erlang:element(2, erlang:element(2, R)) of
head ->
case radiant@internal@tree:match(
erlang:element(2, Router),
get,
Segments
) of
{ok, {Handler@1, Params@1}} ->
{ok,
Handler@1(
{req,
begin
_record = erlang:element(2, R),
{request,
get,
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record)}
end,
Params@1,
erlang:element(4, R)}
)};
{error, _} ->
{error, nil}
end;
_ ->
{error, nil}
end,
case Head_result of
{ok, Resp} ->
{response,
erlang:element(2, Resp),
erlang:element(3, Resp),
<<>>};
{error, _} ->
Allowed = radiant@internal@tree:allowed_methods(
erlang:element(2, Router),
Segments
),
case Allowed of
[] ->
(erlang:element(3, Router))(R);
_ ->
method_not_allowed(
begin
_pipe = Allowed,
_pipe@1 = gleam@list:map(
_pipe,
fun gleam@http:method_to_string/1
),
gleam@string:join(
_pipe@1,
<<", "/utf8>>
)
end
)
end
end
end
end,
Final_handler = gleam@list:fold(
erlang:element(4, Router),
Dispatch,
fun(Handler@2, Mw) -> Mw(Handler@2) end
),
Final_handler({req, Req, maps:new(), maps:new()}).
-file("src/radiant.gleam", 707).
?DOC(
" Like `handle`, but accepts a request with any body type plus a separately\n"
" read `BitArray` body. Useful for Wisp integration where the body is read\n"
" through `wisp.require_bit_array_body` before routing.\n"
"\n"
" ```gleam\n"
" use body <- wisp.require_bit_array_body(req)\n"
" radiant.handle_with(router, req, body)\n"
" ```\n"
).
-spec handle_with(router(), gleam@http@request:request(any()), bitstring()) -> gleam@http@response:response(bitstring()).
handle_with(Router, Req, Body) ->
handle(Router, gleam@http@request:set_body(Req, Body)).
-file("src/radiant.gleam", 1392).
?DOC(
" JSON error response: `{\"error\": \"message\"}` with `application/json` content-type.\n"
"\n"
" ```gleam\n"
" radiant.json_error(404, \"user not found\")\n"
" // → 404 {\"error\":\"user not found\"}\n"
" ```\n"
).
-spec json_error(integer(), binary()) -> gleam@http@response:response(bitstring()).
json_error(Status, Message) ->
Body = gleam@json:to_string(
gleam@json:object([{<<"error"/utf8>>, gleam@json:string(Message)}])
),
_pipe = response(Status, Body),
with_header(
_pipe,
<<"content-type"/utf8>>,
<<"application/json; charset=utf-8"/utf8>>
).
-file("src/radiant.gleam", 1404).
?DOC(" 200 OK with `content-type: application/json`.\n").
-spec json(binary()) -> gleam@http@response:response(bitstring()).
json(Body_text) ->
_pipe = response(200, Body_text),
with_header(
_pipe,
<<"content-type"/utf8>>,
<<"application/json; charset=utf-8"/utf8>>
).
-file("src/radiant.gleam", 1410).
?DOC(" 200 OK with `content-type: text/html`.\n").
-spec html(binary()) -> gleam@http@response:response(bitstring()).
html(Body_text) ->
_pipe = response(200, Body_text),
with_header(
_pipe,
<<"content-type"/utf8>>,
<<"text/html; charset=utf-8"/utf8>>
).
-file("src/radiant.gleam", 1449).
?DOC(
" Sensible default CORS config.\n"
"\n"
" - Origins: `[\"*\"]` (any)\n"
" - Methods: GET, POST, PUT, PATCH, DELETE\n"
" - Headers: `content-type`, `authorization`\n"
" - Max age: 86400 seconds (24 hours)\n"
).
-spec default_cors() -> cors_config().
default_cors() ->
{cors_config,
[<<"*"/utf8>>],
[get, post, put, patch, delete],
[<<"content-type"/utf8>>, <<"authorization"/utf8>>],
86400}.
-file("src/radiant.gleam", 1465).
?DOC(
" CORS middleware. Handles preflight `OPTIONS` requests automatically and\n"
" sets `access-control-allow-*` headers on all responses.\n"
"\n"
" ```gleam\n"
" radiant.new()\n"
" |> radiant.middleware(radiant.cors(radiant.default_cors()))\n"
" ```\n"
).
-spec cors(cors_config()) -> fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))).
cors(Config) ->
fun(Next) ->
fun(Req) ->
Origin = begin
_pipe = header(Req, <<"origin"/utf8>>),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
Allowed = (Origin /= <<""/utf8>>) andalso (gleam@list:contains(
erlang:element(2, Config),
<<"*"/utf8>>
)
orelse gleam@list:contains(erlang:element(2, Config), Origin)),
case method(Req) of
options ->
case Allowed of
true ->
_pipe@1 = no_content(),
_pipe@2 = with_header(
_pipe@1,
<<"access-control-allow-origin"/utf8>>,
Origin
),
_pipe@5 = with_header(
_pipe@2,
<<"access-control-allow-methods"/utf8>>,
begin
_pipe@3 = erlang:element(3, Config),
_pipe@4 = gleam@list:map(
_pipe@3,
fun gleam@http:method_to_string/1
),
gleam@string:join(_pipe@4, <<", "/utf8>>)
end
),
_pipe@6 = with_header(
_pipe@5,
<<"access-control-allow-headers"/utf8>>,
gleam@string:join(
erlang:element(4, Config),
<<", "/utf8>>
)
),
with_header(
_pipe@6,
<<"access-control-max-age"/utf8>>,
erlang:integer_to_binary(
erlang:element(5, Config)
)
);
false ->
no_content()
end;
_ ->
Resp = Next(Req),
case Allowed of
true ->
with_header(
Resp,
<<"access-control-allow-origin"/utf8>>,
Origin
);
false ->
Resp
end
end
end
end.
-file("src/radiant.gleam", 1521).
?DOC(
" Logging middleware. Takes a logging function and calls it before and after\n"
" each request with method, path, and status code.\n"
"\n"
" Works with any logger — woof, io.println, or your own:\n"
"\n"
" ```gleam\n"
" // With io.println:\n"
" radiant.log(io.println)\n"
"\n"
" // With woof:\n"
" radiant.log(fn(msg) { woof.log(logger, woof.Info, msg, []) })\n"
" ```\n"
).
-spec log(fun((binary()) -> any())) -> fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))).
log(Logger) ->
fun(Next) ->
fun(Req) ->
M = gleam@http:method_to_string(method(Req)),
P = req_path(Req),
Logger(<<<<M/binary, " "/utf8>>/binary, P/binary>>),
Resp = Next(Req),
Logger(
<<<<<<<<M/binary, " "/utf8>>/binary, P/binary>>/binary,
" → "/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(2, Resp)))/binary>>
),
Resp
end
end.
-file("src/radiant.gleam", 1546).
?DOC(
" Rescue middleware. Catches Erlang exceptions (panics) in handlers and\n"
" returns a 500 response instead of crashing the process.\n"
"\n"
" The callback receives the exception for logging or error reporting.\n"
"\n"
" ```gleam\n"
" radiant.new()\n"
" |> radiant.middleware(radiant.rescue(fn(err) {\n"
" io.debug(err)\n"
" radiant.response(500, \"Internal server error\")\n"
" }))\n"
" ```\n"
).
-spec rescue(
fun((exception:exception()) -> gleam@http@response:response(bitstring()))
) -> fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))).
rescue(On_error) ->
fun(Next) ->
fun(Req) -> case exception_ffi:rescue(fun() -> Next(Req) end) of
{ok, Resp} ->
Resp;
{error, Err} ->
On_error(Err)
end end
end.
-file("src/radiant.gleam", 1580).
?DOC(
" A middleware that parses the request body as JSON and stores it in the\n"
" request context under the given typed key.\n"
"\n"
" If the body is not valid JSON or does not match the decoder,\n"
" returns `400 Bad Request` immediately.\n"
"\n"
" ```gleam\n"
" pub const user_key: radiant.Key(User) = radiant.key(\"user\")\n"
"\n"
" let user_decoder = {\n"
" use name <- decode.field(\"name\", decode.string)\n"
" decode.success(User(name))\n"
" }\n"
"\n"
" radiant.new()\n"
" |> radiant.middleware(radiant.json_body(user_key, user_decoder))\n"
" |> radiant.post(\"/users\", fn(req) {\n"
" let assert Ok(user) = radiant.get_context(req, user_key)\n"
" radiant.ok(\"Hello \" <> user.name)\n"
" })\n"
" ```\n"
).
-spec json_body(key(PTP), gleam@dynamic@decode:decoder(PTP)) -> fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))).
json_body(Key, Decoder) ->
fun(Next) -> fun(Req) -> case body(Req) of
<<>> ->
Next(Req);
_ ->
case text_body(Req) of
{ok, B} ->
case gleam@json:parse(B, Decoder) of
{ok, Val} ->
Next(set_context(Req, Key, Val));
{error, _} ->
bad_request()
end;
{error, _} ->
bad_request()
end
end end end.
-file("src/radiant.gleam", 1655).
-spec mime_from_path(binary()) -> binary().
mime_from_path(Path) ->
Ext = begin
_pipe = Path,
_pipe@1 = gleam@string:split(_pipe, <<"."/utf8>>),
_pipe@2 = gleam@list:last(_pipe@1),
_pipe@3 = gleam@result:unwrap(_pipe@2, <<""/utf8>>),
string:lowercase(_pipe@3)
end,
case Ext of
<<"html"/utf8>> ->
<<"text/html"/utf8>>;
<<"htm"/utf8>> ->
<<"text/html"/utf8>>;
<<"css"/utf8>> ->
<<"text/css"/utf8>>;
<<"js"/utf8>> ->
<<"application/javascript"/utf8>>;
<<"json"/utf8>> ->
<<"application/json"/utf8>>;
<<"png"/utf8>> ->
<<"image/png"/utf8>>;
<<"jpg"/utf8>> ->
<<"image/jpeg"/utf8>>;
<<"jpeg"/utf8>> ->
<<"image/jpeg"/utf8>>;
<<"gif"/utf8>> ->
<<"image/gif"/utf8>>;
<<"svg"/utf8>> ->
<<"image/svg+xml"/utf8>>;
<<"txt"/utf8>> ->
<<"text/plain"/utf8>>;
_ ->
<<"application/octet-stream"/utf8>>
end.
-file("src/radiant.gleam", 1608).
?DOC(
" A middleware that serves static files from a directory.\n"
"\n"
" It strips the `prefix` from the request path and looks for the remaining\n"
" path inside the `directory`.\n"
"\n"
" If a file is found, it's served with a guessed Mime-Type.\n"
" Otherwise, it falls back to the next handler (usualy a 404 fallback).\n"
).
-spec serve_static(binary(), binary(), file_system()) -> fun((fun((req()) -> gleam@http@response:response(bitstring()))) -> fun((req()) -> gleam@http@response:response(bitstring()))).
serve_static(Prefix, Directory, Fs) ->
Prefix@1 = case gleam_stdlib:string_starts_with(Prefix, <<"/"/utf8>>) of
true ->
Prefix;
false ->
<<"/"/utf8, Prefix/binary>>
end,
fun(Next) ->
fun(Req) ->
Path = req_path(Req),
case gleam_stdlib:string_starts_with(Path, Prefix@1) of
true ->
Rel_path = begin
_pipe = gleam@string:drop_start(
Path,
string:length(Prefix@1)
),
_pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>),
_pipe@2 = gleam@list:filter(
_pipe@1,
fun(S) ->
(S /= <<""/utf8>>) andalso (S /= <<".."/utf8>>)
end
),
gleam@string:join(_pipe@2, <<"/"/utf8>>)
end,
Full_path = case Directory of
<<"."/utf8>> ->
Rel_path;
_ ->
<<<<Directory/binary, "/"/utf8>>/binary,
Rel_path/binary>>
end,
case (erlang:element(3, Fs))(Full_path) of
true ->
case (erlang:element(2, Fs))(Full_path) of
{ok, Bits} ->
Mime = mime_from_path(Full_path),
_pipe@3 = gleam@http@response:new(200),
_pipe@4 = gleam@http@response:set_body(
_pipe@3,
Bits
),
gleam@http@response:set_header(
_pipe@4,
<<"content-type"/utf8>>,
Mime
);
{error, _} ->
Next(Req)
end;
false ->
Next(Req)
end;
false ->
Next(Req)
end
end
end.
-file("src/radiant.gleam", 1685).
?DOC(
" Create a test request with the given method and path.\n"
" Supports query strings: `test_request(Get, \"/search?q=gleam\")`.\n"
"\n"
" Note: import `gleam/http.{Get, Post, ...}` for method constructors.\n"
).
-spec test_request(gleam@http:method(), binary()) -> gleam@http@request:request(bitstring()).
test_request(Method, Raw_path) ->
case gleam@string:split_once(Raw_path, <<"?"/utf8>>) of
{ok, {P, Q}} ->
_pipe = gleam@http@request:new(),
_pipe@1 = gleam@http@request:set_method(_pipe, Method),
_pipe@2 = gleam@http@request:set_path(_pipe@1, P),
_pipe@3 = (fun(R) ->
{request,
erlang:element(2, R),
erlang:element(3, R),
erlang:element(4, R),
erlang:element(5, R),
erlang:element(6, R),
erlang:element(7, R),
erlang:element(8, R),
{some, Q}}
end)(_pipe@2),
gleam@http@request:set_body(_pipe@3, <<>>);
{error, nil} ->
_pipe@4 = gleam@http@request:new(),
_pipe@5 = gleam@http@request:set_method(_pipe@4, Method),
_pipe@6 = gleam@http@request:set_path(_pipe@5, Raw_path),
gleam@http@request:set_body(_pipe@6, <<>>)
end.
-file("src/radiant.gleam", 1702).
?DOC(" Shortcut: create a GET test request.\n").
-spec test_get(binary()) -> gleam@http@request:request(bitstring()).
test_get(Raw_path) ->
test_request(get, Raw_path).
-file("src/radiant.gleam", 1707).
?DOC(" Shortcut: create a POST test request with a UTF-8 body.\n").
-spec test_post(binary(), binary()) -> gleam@http@request:request(bitstring()).
test_post(Raw_path, Body_text) ->
_pipe = test_request(post, Raw_path),
gleam@http@request:set_body(_pipe, <<Body_text/binary>>).
-file("src/radiant.gleam", 1713).
?DOC(" Shortcut: create a PUT test request with a UTF-8 body.\n").
-spec test_put(binary(), binary()) -> gleam@http@request:request(bitstring()).
test_put(Raw_path, Body_text) ->
_pipe = test_request(put, Raw_path),
gleam@http@request:set_body(_pipe, <<Body_text/binary>>).
-file("src/radiant.gleam", 1719).
?DOC(" Shortcut: create a PATCH test request with a UTF-8 body.\n").
-spec test_patch(binary(), binary()) -> gleam@http@request:request(bitstring()).
test_patch(Raw_path, Body_text) ->
_pipe = test_request(patch, Raw_path),
gleam@http@request:set_body(_pipe, <<Body_text/binary>>).
-file("src/radiant.gleam", 1725).
?DOC(" Shortcut: create a DELETE test request.\n").
-spec test_delete(binary()) -> gleam@http@request:request(bitstring()).
test_delete(Raw_path) ->
test_request(delete, Raw_path).
-file("src/radiant.gleam", 1730).
?DOC(" Shortcut: create a HEAD test request.\n").
-spec test_head(binary()) -> gleam@http@request:request(bitstring()).
test_head(Raw_path) ->
test_request(head, Raw_path).
-file("src/radiant.gleam", 1735).
?DOC(" Shortcut: create an OPTIONS test request.\n").
-spec test_options(binary()) -> gleam@http@request:request(bitstring()).
test_options(Raw_path) ->
test_request(options, Raw_path).
-file("src/radiant.gleam", 1745).
?DOC(
" Assert that a response has the expected status code.\n"
" Panics if the status doesn't match.\n"
).
-spec should_have_status(gleam@http@response:response(bitstring()), integer()) -> gleam@http@response:response(bitstring()).
should_have_status(Resp, Expected) ->
case erlang:element(2, Resp) =:= Expected of
true ->
Resp;
false ->
Msg = <<<<<<"Radiant Test: Expected status "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(2, Resp)))/binary>>,
erlang:error(#{gleam_error => panic,
message => Msg,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_status"/utf8>>,
line => 1757})
end.
-file("src/radiant.gleam", 1764).
?DOC(
" Assert that a response has the expected body.\n"
" Panics if the body doesn't match.\n"
).
-spec should_have_body(gleam@http@response:response(bitstring()), binary()) -> gleam@http@response:response(bitstring()).
should_have_body(Resp, Expected) ->
Expected_bits = <<Expected/binary>>,
case erlang:element(4, Resp) =:= Expected_bits of
true ->
Resp;
false ->
Actual = begin
_pipe = gleam@bit_array:to_string(erlang:element(4, Resp)),
gleam@result:unwrap(_pipe, <<"<non-utf8>"/utf8>>)
end,
erlang:error(#{gleam_error => panic,
message => (<<<<<<<<"Radiant Test: Expected body \""/utf8,
Expected/binary>>/binary,
"\", got \""/utf8>>/binary,
Actual/binary>>/binary,
"\""/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_body"/utf8>>,
line => 1773})
end.
-file("src/radiant.gleam", 1786).
?DOC(
" Assert that a response has the expected header value.\n"
" Panics if the header is missing or doesn't match.\n"
).
-spec should_have_header(
gleam@http@response:response(bitstring()),
binary(),
binary()
) -> gleam@http@response:response(bitstring()).
should_have_header(Resp, Name, Expected) ->
case gleam@http@response:get_header(Resp, Name) of
{ok, Val} when Val =:= Expected ->
Resp;
{ok, Val@1} ->
erlang:error(#{gleam_error => panic,
message => (<<<<<<<<<<<<"Radiant Test: Expected header '"/utf8,
Name/binary>>/binary,
"' to be '"/utf8>>/binary,
Expected/binary>>/binary,
"', got '"/utf8>>/binary,
Val@1/binary>>/binary,
"'"/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_header"/utf8>>,
line => 1794});
{error, nil} ->
erlang:error(#{gleam_error => panic,
message => (<<<<"Radiant Test: Missing expected header '"/utf8,
Name/binary>>/binary,
"'"/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_header"/utf8>>,
line => 1805})
end.
-file("src/radiant.gleam", 1813).
?DOC(
" Parse the response body as JSON and verify it matches the decoder.\n"
" Returns the decoded value for further assertions.\n"
" Panics if parsing fails.\n"
).
-spec should_have_json_body(
gleam@http@response:response(bitstring()),
gleam@dynamic@decode:decoder(PUH)
) -> PUH.
should_have_json_body(Resp, Decoder) ->
Body = case gleam@bit_array:to_string(erlang:element(4, Resp)) of
{ok, S} ->
S;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Radiant Test: Response body is not valid UTF-8"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_json_body"/utf8>>,
line => 1819})
end,
case gleam@json:parse(Body, Decoder) of
{ok, Val} ->
Val;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Radiant Test: Failed to decode JSON response body"/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"radiant"/utf8>>,
function => <<"should_have_json_body"/utf8>>,
line => 1824})
end.