Current section
Files
Jump to
Current section
Files
src/dream_http_client@recording.erl
-module(dream_http_client@recording).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream_http_client/recording.gleam").
-export([encode_recording_file/1, decode_recording_file/1]).
-export_type([recorded_request/0, recorded_response/0, chunk/0, recording/0, recording_file/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(
" Recording format types and JSON codecs\n"
"\n"
" Defines the structure for storing HTTP request/response recordings\n"
" in a custom JSON format that supports both blocking and streaming responses.\n"
).
-type recorded_request() :: {recorded_request,
gleam@http:method(),
gleam@http:scheme(),
binary(),
gleam@option:option(integer()),
binary(),
gleam@option:option(binary()),
list({binary(), binary()}),
binary()}.
-type recorded_response() :: {blocking_response,
integer(),
list({binary(), binary()}),
binary()} |
{streaming_response, integer(), list({binary(), binary()}), list(chunk())}.
-type chunk() :: {chunk, bitstring(), integer()}.
-type recording() :: {recording, recorded_request(), recorded_response()}.
-type recording_file() :: {recording_file, binary(), list(recording())}.
-file("src/dream_http_client/recording.gleam", 66).
-spec identity_json(gleam@json:json()) -> gleam@json:json().
identity_json(Value) ->
Value.
-file("src/dream_http_client/recording.gleam", 119).
-spec encode_chunk(chunk()) -> gleam@json:json().
encode_chunk(Chunk) ->
Data_str = case gleam@bit_array:to_string(erlang:element(2, Chunk)) of
{ok, S} ->
S;
{error, _} ->
<<""/utf8>>
end,
gleam@json:object(
[{<<"data"/utf8>>, gleam@json:string(Data_str)},
{<<"delay_ms"/utf8>>, gleam@json:int(erlang:element(3, Chunk))}]
).
-file("src/dream_http_client/recording.gleam", 144).
-spec encode_header_pair({binary(), binary()}) -> gleam@json:json().
encode_header_pair(Header) ->
gleam@json:array(
[gleam@json:string(erlang:element(1, Header)),
gleam@json:string(erlang:element(2, Header))],
fun identity_json/1
).
-file("src/dream_http_client/recording.gleam", 139).
-spec encode_headers(list({binary(), binary()})) -> gleam@json:json().
encode_headers(Headers) ->
Header_arrays = gleam@list:map(Headers, fun encode_header_pair/1),
gleam@json:array(Header_arrays, fun identity_json/1).
-file("src/dream_http_client/recording.gleam", 98).
-spec encode_recorded_response(recorded_response()) -> gleam@json:json().
encode_recorded_response(Resp) ->
case Resp of
{blocking_response, Status, Headers, Body} ->
gleam@json:object(
[{<<"mode"/utf8>>, gleam@json:string(<<"blocking"/utf8>>)},
{<<"status"/utf8>>, gleam@json:int(Status)},
{<<"headers"/utf8>>, encode_headers(Headers)},
{<<"body"/utf8>>, gleam@json:string(Body)}]
);
{streaming_response, Status@1, Headers@1, Chunks} ->
Chunks_json = gleam@list:map(Chunks, fun encode_chunk/1),
gleam@json:object(
[{<<"mode"/utf8>>, gleam@json:string(<<"streaming"/utf8>>)},
{<<"status"/utf8>>, gleam@json:int(Status@1)},
{<<"headers"/utf8>>, encode_headers(Headers@1)},
{<<"chunks"/utf8>>,
gleam@json:array(Chunks_json, fun identity_json/1)}]
)
end.
-file("src/dream_http_client/recording.gleam", 151).
-spec encode_method(gleam@http:method()) -> gleam@json:json().
encode_method(Method) ->
Method_str = case Method of
get ->
<<"GET"/utf8>>;
post ->
<<"POST"/utf8>>;
put ->
<<"PUT"/utf8>>;
delete ->
<<"DELETE"/utf8>>;
patch ->
<<"PATCH"/utf8>>;
head ->
<<"HEAD"/utf8>>;
options ->
<<"OPTIONS"/utf8>>;
trace ->
<<"TRACE"/utf8>>;
connect ->
<<"CONNECT"/utf8>>;
{other, S} ->
string:uppercase(S)
end,
gleam@json:string(Method_str).
-file("src/dream_http_client/recording.gleam", 167).
-spec encode_scheme(gleam@http:scheme()) -> gleam@json:json().
encode_scheme(Scheme) ->
Scheme_str = case Scheme of
http ->
<<"http"/utf8>>;
https ->
<<"https"/utf8>>
end,
gleam@json:string(Scheme_str).
-file("src/dream_http_client/recording.gleam", 77).
-spec encode_recorded_request(recorded_request()) -> gleam@json:json().
encode_recorded_request(Req) ->
Port_json = case erlang:element(5, Req) of
{some, P} ->
gleam@json:int(P);
none ->
gleam@json:null()
end,
Query_json = case erlang:element(7, Req) of
{some, Q} ->
gleam@json:string(Q);
none ->
gleam@json:null()
end,
gleam@json:object(
[{<<"method"/utf8>>, encode_method(erlang:element(2, Req))},
{<<"scheme"/utf8>>, encode_scheme(erlang:element(3, Req))},
{<<"host"/utf8>>, gleam@json:string(erlang:element(4, Req))},
{<<"port"/utf8>>, Port_json},
{<<"path"/utf8>>, gleam@json:string(erlang:element(6, Req))},
{<<"query"/utf8>>, Query_json},
{<<"headers"/utf8>>, encode_headers(erlang:element(8, Req))},
{<<"body"/utf8>>, gleam@json:string(erlang:element(9, Req))}]
).
-file("src/dream_http_client/recording.gleam", 70).
-spec encode_recording(recording()) -> gleam@json:json().
encode_recording(Recording) ->
gleam@json:object(
[{<<"request"/utf8>>,
encode_recorded_request(erlang:element(2, Recording))},
{<<"response"/utf8>>,
encode_recorded_response(erlang:element(3, Recording))}]
).
-file("src/dream_http_client/recording.gleam", 58).
-spec encode_recording_file(recording_file()) -> gleam@json:json().
encode_recording_file(File) ->
Entries_json = gleam@list:map(
erlang:element(3, File),
fun encode_recording/1
),
gleam@json:object(
[{<<"version"/utf8>>, gleam@json:string(erlang:element(2, File))},
{<<"entries"/utf8>>,
gleam@json:array(Entries_json, fun identity_json/1)}]
).
-file("src/dream_http_client/recording.gleam", 199).
-spec format_json_error(gleam@json:decode_error()) -> binary().
format_json_error(Error) ->
case Error of
unexpected_end_of_input ->
<<"Unexpected end of JSON input"/utf8>>;
{unexpected_byte, Msg} ->
<<"Unexpected byte: "/utf8, Msg/binary>>;
{unexpected_sequence, Msg@1} ->
<<"Unexpected sequence: "/utf8, Msg@1/binary>>;
{unable_to_decode, Errors} ->
<<"Unable to decode: "/utf8, (gleam@string:inspect(Errors))/binary>>
end.
-file("src/dream_http_client/recording.gleam", 216).
-spec format_single_decode_error(gleam@dynamic@decode:decode_error()) -> binary().
format_single_decode_error(Error) ->
{decode_error, Expected, Found, Path} = Error,
Field_path = gleam@string:join(Path, <<"."/utf8>>),
<<<<<<<<<<"Expected "/utf8, Expected/binary>>/binary, ", found "/utf8>>/binary,
Found/binary>>/binary,
" at "/utf8>>/binary,
Field_path/binary>>.
-file("src/dream_http_client/recording.gleam", 209).
-spec format_decode_errors(list(gleam@dynamic@decode:decode_error())) -> binary().
format_decode_errors(Errors) ->
case gleam@list:first(Errors) of
{ok, Error} ->
format_single_decode_error(Error);
{error, _} ->
<<"Decode error with no details"/utf8>>
end.
-file("src/dream_http_client/recording.gleam", 293).
-spec decode_blocking_response_decoder(integer(), list({binary(), binary()})) -> gleam@dynamic@decode:decoder(recorded_response()).
decode_blocking_response_decoder(Status, Headers) ->
gleam@dynamic@decode:field(
<<"body"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Body) ->
gleam@dynamic@decode:success(
{blocking_response, Status, Headers, Body}
)
end
).
-file("src/dream_http_client/recording.gleam", 313).
-spec decode_chunk_decoder() -> gleam@dynamic@decode:decoder(chunk()).
decode_chunk_decoder() ->
gleam@dynamic@decode:field(
<<"data"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Data_str) ->
gleam@dynamic@decode:field(
<<"delay_ms"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Delay_ms) ->
Data = <<Data_str/binary>>,
gleam@dynamic@decode:success({chunk, Data, Delay_ms})
end
)
end
).
-file("src/dream_http_client/recording.gleam", 301).
-spec decode_streaming_response_decoder(integer(), list({binary(), binary()})) -> gleam@dynamic@decode:decoder(recorded_response()).
decode_streaming_response_decoder(Status, Headers) ->
gleam@dynamic@decode:field(
<<"chunks"/utf8>>,
gleam@dynamic@decode:list(decode_chunk_decoder()),
fun(Chunks) ->
gleam@dynamic@decode:success(
{streaming_response, Status, Headers, Chunks}
)
end
).
-file("src/dream_http_client/recording.gleam", 321).
-spec decode_header_pair_decoder() -> gleam@dynamic@decode:decoder({binary(),
binary()}).
decode_header_pair_decoder() ->
_pipe = gleam@dynamic@decode:at(
[0],
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
gleam@dynamic@decode:then(
_pipe,
fun(Name) ->
_pipe@1 = gleam@dynamic@decode:at(
[1],
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
gleam@dynamic@decode:map(_pipe@1, fun(Value) -> {Name, Value} end)
end
).
-file("src/dream_http_client/recording.gleam", 278).
-spec decode_recorded_response_decoder() -> gleam@dynamic@decode:decoder(recorded_response()).
decode_recorded_response_decoder() ->
gleam@dynamic@decode:field(
<<"mode"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Mode) ->
gleam@dynamic@decode:field(
<<"status"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Status) ->
gleam@dynamic@decode:field(
<<"headers"/utf8>>,
gleam@dynamic@decode:list(decode_header_pair_decoder()),
fun(Headers) -> case Mode of
<<"blocking"/utf8>> ->
decode_blocking_response_decoder(
Status,
Headers
);
<<"streaming"/utf8>> ->
decode_streaming_response_decoder(
Status,
Headers
);
_ ->
decode_blocking_response_decoder(
Status,
Headers
)
end end
)
end
)
end
).
-file("src/dream_http_client/recording.gleam", 329).
-spec parse_method_string(binary()) -> {ok, gleam@http:method()} |
{error, binary()}.
parse_method_string(Method_str) ->
case string:lowercase(Method_str) of
<<"get"/utf8>> ->
{ok, get};
<<"post"/utf8>> ->
{ok, post};
<<"put"/utf8>> ->
{ok, put};
<<"delete"/utf8>> ->
{ok, delete};
<<"patch"/utf8>> ->
{ok, patch};
<<"head"/utf8>> ->
{ok, head};
<<"options"/utf8>> ->
{ok, options};
<<"trace"/utf8>> ->
{ok, trace};
<<"connect"/utf8>> ->
{ok, connect};
_ ->
{ok, {other, Method_str}}
end.
-file("src/dream_http_client/recording.gleam", 344).
-spec parse_scheme_string(binary()) -> {ok, gleam@http:scheme()} |
{error, binary()}.
parse_scheme_string(Scheme_str) ->
case Scheme_str of
<<"http"/utf8>> ->
{ok, http};
<<"https"/utf8>> ->
{ok, https};
_ ->
{error, <<"Unknown scheme: "/utf8, Scheme_str/binary>>}
end.
-file("src/dream_http_client/recording.gleam", 228).
-spec decode_recorded_request_decoder() -> gleam@dynamic@decode:decoder(recorded_request()).
decode_recorded_request_decoder() ->
gleam@dynamic@decode:field(
<<"method"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Method_str) ->
gleam@dynamic@decode:field(
<<"scheme"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Scheme_str) ->
gleam@dynamic@decode:field(
<<"host"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Host) ->
gleam@dynamic@decode:field(
<<"port"/utf8>>,
gleam@dynamic@decode:optional(
{decoder,
fun gleam@dynamic@decode:decode_int/1}
),
fun(Port) ->
gleam@dynamic@decode:field(
<<"path"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Path) ->
gleam@dynamic@decode:field(
<<"query"/utf8>>,
gleam@dynamic@decode:optional(
{decoder,
fun gleam@dynamic@decode:decode_string/1}
),
fun(Query) ->
gleam@dynamic@decode:field(
<<"headers"/utf8>>,
gleam@dynamic@decode:list(
decode_header_pair_decoder(
)
),
fun(Headers) ->
gleam@dynamic@decode:field(
<<"body"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Body) ->
Method = case parse_method_string(
Method_str
) of
{ok, M} ->
M;
{error,
_} ->
{other,
Method_str}
end,
case parse_scheme_string(
Scheme_str
) of
{ok,
Scheme} ->
gleam@dynamic@decode:success(
{recorded_request,
Method,
Scheme,
Host,
Port,
Path,
Query,
Headers,
Body}
);
{error,
_} ->
gleam@dynamic@decode:success(
{recorded_request,
Method,
http,
Host,
Port,
Path,
Query,
Headers,
Body}
)
end
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/dream_http_client/recording.gleam", 222).
-spec decode_recording_decoder() -> gleam@dynamic@decode:decoder(recording()).
decode_recording_decoder() ->
gleam@dynamic@decode:field(
<<"request"/utf8>>,
decode_recorded_request_decoder(),
fun(Request) ->
gleam@dynamic@decode:field(
<<"response"/utf8>>,
decode_recorded_response_decoder(),
fun(Response) ->
gleam@dynamic@decode:success({recording, Request, Response})
end
)
end
).
-file("src/dream_http_client/recording.gleam", 190).
-spec decode_recording_file_decoder() -> gleam@dynamic@decode:decoder(recording_file()).
decode_recording_file_decoder() ->
gleam@dynamic@decode:field(
<<"version"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Version) ->
gleam@dynamic@decode:field(
<<"entries"/utf8>>,
gleam@dynamic@decode:list(decode_recording_decoder()),
fun(Entries) ->
gleam@dynamic@decode:success(
{recording_file, Version, Entries}
)
end
)
end
).
-file("src/dream_http_client/recording.gleam", 179).
-spec decode_recording_file(binary()) -> {ok, recording_file()} |
{error, binary()}.
decode_recording_file(Json_string) ->
gleam@result:'try'(
begin
_pipe = gleam@json:parse(
Json_string,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
),
gleam@result:map_error(_pipe, fun format_json_error/1)
end,
fun(Json_value) ->
_pipe@1 = gleam@dynamic@decode:run(
Json_value,
decode_recording_file_decoder()
),
gleam@result:map_error(_pipe@1, fun format_decode_errors/1)
end
).