-module(datastar_gleam@wisp).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/datastar_gleam/wisp.gleam").
-export([is_datastar_request/1, read_signals/2]).
-export_type([read_signals_error/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.
-type read_signals_error() :: missing_header |
invalid_query |
invalid_body |
{json_decode_error, gleam@json:decode_error()}.
-file("src/datastar_gleam/wisp.gleam", 19).
?DOC(
" Check whether a Wisp request was initiated by Datastar.\n"
"\n"
" This inspects the `datastar-request` header that the Datastar frontend\n"
" automatically adds to every outgoing request.\n"
).
-spec is_datastar_request(
gleam@http@request:request(wisp@internal:connection())
) -> boolean().
is_datastar_request(Req) ->
case gleam@http@request:get_header(Req, <<"datastar-request"/utf8>>) of
{ok, _} ->
true;
{error, _} ->
false
end.
-file("src/datastar_gleam/wisp.gleam", 83).
-spec read_signals_from_body(
gleam@http@request:request(wisp@internal:connection()),
gleam@dynamic@decode:decoder(ABDI)
) -> {ok, ABDI} | {error, read_signals_error()}.
read_signals_from_body(Req, Decoder) ->
case wisp:read_body_bits(Req) of
{error, _} ->
{error, invalid_body};
{ok, Bits} ->
case gleam@bit_array:to_string(Bits) of
{error, nil} ->
{error, invalid_body};
{ok, Body} ->
case gleam@json:parse(Body, Decoder) of
{ok, Val} ->
{ok, Val};
{error, Err} ->
{error, {json_decode_error, Err}}
end
end
end.
-file("src/datastar_gleam/wisp.gleam", 67).
-spec read_signals_from_query(
gleam@http@request:request(wisp@internal:connection()),
gleam@dynamic@decode:decoder(ABDE)
) -> {ok, ABDE} | {error, read_signals_error()}.
read_signals_from_query(Req, Decoder) ->
Query = wisp:get_query(Req),
case gleam@list:key_find(Query, <<"datastar"/utf8>>) of
{error, nil} ->
{error, invalid_query};
{ok, Raw} ->
case gleam@json:parse(Raw, Decoder) of
{ok, Val} ->
{ok, Val};
{error, Err} ->
{error, {json_decode_error, Err}}
end
end.
-file("src/datastar_gleam/wisp.gleam", 52).
?DOC(
" Read Datastar signals from a Wisp request.\n"
"\n"
" For **GET** requests, expects `?datastar=url_encoded_json`.\n"
" For **POST/PUT/PATCH** requests, expects a JSON body.\n"
"\n"
" ```gleam\n"
" import gleam/dynamic/decode\n"
"\n"
" let decoder = decode.at([\"delay\"], decode.int)\n"
" case datastar_wisp.read_signals(req, decoder) {\n"
" Ok(signals) -> // use signals\n"
" Error(datastar_wisp.MissingHeader) -> // not a datastar request\n"
" }\n"
" ```\n"
).
-spec read_signals(
gleam@http@request:request(wisp@internal:connection()),
gleam@dynamic@decode:decoder(ABDA)
) -> {ok, ABDA} | {error, read_signals_error()}.
read_signals(Req, Decoder) ->
case is_datastar_request(Req) of
false ->
{error, missing_header};
true ->
case erlang:element(2, Req) of
get ->
read_signals_from_query(Req, Decoder);
_ ->
read_signals_from_body(Req, Decoder)
end
end.