-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/\"), ...]\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//posts/\", [\n" " #(\"id\", \"42\"), #(\"pid\", \"7\"),\n" " ])\n" " // → Ok(\"/users/42/posts/7\")\n" "\n" " radiant.path_for(\"/users/\", [])\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/\", user_id, handler)\n" "\n" " // URL building — user_id.name is always in sync with the route\n" " radiant.path_for1(\"/users/\", 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, 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, [], <>}. -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(<<<>/binary, P/binary>>), Resp = Next(Req), Logger( <<<<<<<>/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; _ -> <<<>/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, <>). -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, <>). -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, <>). -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 => <>, 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 = <>, 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, <<""/utf8>>) end, erlang:error(#{gleam_error => panic, message => (<<<<<<<<"Radiant Test: Expected body \""/utf8, Expected/binary>>/binary, "\", got \""/utf8>>/binary, Actual/binary>>/binary, "\""/utf8>>), file => <>, 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 => <>, 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 => <>, 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 => <>, 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 => <>, module => <<"radiant"/utf8>>, function => <<"should_have_json_body"/utf8>>, line => 1824}) end.