Current section

Files

Jump to
oaspec src oaspec@internal@codegen@client_response.erl
Raw

src/oaspec@internal@codegen@client_response.erl

-module(oaspec@internal@codegen@client_response).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/internal/codegen/client_response.gleam").
-export([generate_empty_content_response/4, generate_multi_content_response/7, build_headers_record/3, inline_schema_to_decoder/1, get_response_decode_expr/4, generate_single_content_response/8]).
-export_type([headers_record/0, header_field_type/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(false).
-type headers_record() :: {headers_record, list(binary()), binary()}.
-type header_field_type() :: string_header |
int_header |
float_header |
bool_header.
-file("src/oaspec/internal/codegen/client_response.gleam", 23).
?DOC(false).
-spec status_branch_pattern(oaspec@internal@util@http:http_status_code()) -> binary().
status_branch_pattern(Status_code) ->
case Status_code of
default_status ->
<<"status"/utf8>>;
_ ->
oaspec@internal@util@http:status_code_to_int_pattern(Status_code)
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 33).
?DOC(false).
-spec prepend_default_status(
binary(),
oaspec@internal@util@http:http_status_code()
) -> binary().
prepend_default_status(Arg, Status_code) ->
case Status_code of
default_status ->
case Arg of
<<""/utf8>> ->
<<"status"/utf8>>;
_ ->
<<"status, "/utf8, Arg/binary>>
end;
_ ->
Arg
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 219).
?DOC(false).
-spec emit_pre_statements(
gleam@string_tree:string_tree(),
gleam@option:option(headers_record())
) -> gleam@string_tree:string_tree().
emit_pre_statements(Sb, Headers) ->
case Headers of
{some, {headers_record, Stmts, _}} ->
gleam@list:fold(
Stmts,
Sb,
fun(Acc, Line) ->
oaspec@internal@util@string_extra:indent(Acc, 3, Line)
end
);
none ->
Sb
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 169).
?DOC(false).
-spec empty_body_branch(
gleam@string_tree:string_tree(),
oaspec@internal@util@http:http_status_code(),
binary(),
gleam@option:option(headers_record())
) -> gleam@string_tree:string_tree().
empty_body_branch(Sb, Status_code, Variant_name, Headers) ->
case Headers of
{some, {headers_record, [_ | _], Expr}} ->
_pipe = Sb,
_pipe@1 = oaspec@internal@util@string_extra:indent(
_pipe,
2,
<<(status_branch_pattern(Status_code))/binary, " -> {"/utf8>>
),
_pipe@2 = emit_pre_statements(_pipe@1, Headers),
_pipe@3 = oaspec@internal@util@string_extra:indent(
_pipe@2,
3,
<<<<<<<<"Ok("/utf8, Variant_name/binary>>/binary, "("/utf8>>/binary,
(prepend_default_status(Expr, Status_code))/binary>>/binary,
"))"/utf8>>
),
oaspec@internal@util@string_extra:indent(_pipe@3, 2, <<"}"/utf8>>);
{some, {headers_record, _, Expr@1}} ->
_pipe@4 = Sb,
oaspec@internal@util@string_extra:indent(
_pipe@4,
2,
<<<<<<<<<<(status_branch_pattern(Status_code))/binary,
" -> Ok("/utf8>>/binary,
Variant_name/binary>>/binary,
"("/utf8>>/binary,
(prepend_default_status(Expr@1, Status_code))/binary>>/binary,
"))"/utf8>>
);
none ->
_pipe@5 = Sb,
oaspec@internal@util@string_extra:indent(
_pipe@5,
2,
<<<<<<<<(status_branch_pattern(Status_code))/binary,
" -> Ok("/utf8>>/binary,
Variant_name/binary>>/binary,
(case Status_code of
default_status ->
<<"(status)"/utf8>>;
_ ->
<<""/utf8>>
end)/binary>>/binary,
")"/utf8>>
)
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 234).
?DOC(false).
-spec append_headers_arg(binary(), gleam@option:option(headers_record())) -> binary().
append_headers_arg(Body_arg, Headers) ->
case Headers of
{some, {headers_record, _, Expr}} ->
<<<<Body_arg/binary, ", "/utf8>>/binary, Expr/binary>>;
none ->
Body_arg
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 138).
?DOC(false).
-spec body_branch(
gleam@string_tree:string_tree(),
oaspec@internal@util@http:http_status_code(),
binary(),
binary(),
gleam@option:option(headers_record()),
fun((gleam@string_tree:string_tree()) -> gleam@string_tree:string_tree())
) -> gleam@string_tree:string_tree().
body_branch(Sb, Status_code, Variant_name, Body_arg, Headers, Extract_body) ->
_pipe = Sb,
_pipe@1 = oaspec@internal@util@string_extra:indent(
_pipe,
2,
<<(status_branch_pattern(Status_code))/binary, " -> {"/utf8>>
),
_pipe@2 = Extract_body(_pipe@1),
_pipe@3 = emit_pre_statements(_pipe@2, Headers),
_pipe@4 = oaspec@internal@util@string_extra:indent(
_pipe@3,
3,
<<<<<<<<"Ok("/utf8, Variant_name/binary>>/binary, "("/utf8>>/binary,
(prepend_default_status(
append_headers_arg(Body_arg, Headers),
Status_code
))/binary>>/binary,
"))"/utf8>>
),
oaspec@internal@util@string_extra:indent(_pipe@4, 2, <<"}"/utf8>>).
-file("src/oaspec/internal/codegen/client_response.gleam", 249).
?DOC(false).
-spec generate_empty_content_response(
gleam@string_tree:string_tree(),
oaspec@internal@util@http:http_status_code(),
binary(),
gleam@option:option(headers_record())
) -> gleam@string_tree:string_tree().
generate_empty_content_response(Sb, Status_code, Variant_name, Headers) ->
empty_body_branch(Sb, Status_code, Variant_name, Headers).
-file("src/oaspec/internal/codegen/client_response.gleam", 261).
?DOC(false).
-spec generate_multi_content_response(
gleam@string_tree:string_tree(),
oaspec@internal@util@http:http_status_code(),
binary(),
list({binary(), oaspec@openapi@spec:media_type()}),
binary(),
oaspec@internal@codegen@context:context(),
gleam@option:option(headers_record())
) -> gleam@string_tree:string_tree().
generate_multi_content_response(Sb, Status_code, Variant_name, _, _, _, Headers) ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"text"/utf8>>,
Headers,
fun(Sb@1) ->
oaspec@internal@util@string_extra:indent(
Sb@1,
3,
<<"use text <- result.try(text_body(resp.body))"/utf8>>
)
end
).
-file("src/oaspec/internal/codegen/client_response.gleam", 375).
?DOC(false).
-spec unreachable_header_panic(binary(), binary()) -> binary().
unreachable_header_panic(Header_name, Kind) ->
<<<<<<<<<<<<<<"oaspec internal error: codegen reached an unsupported response header"/utf8,
" schema (header '"/utf8>>/binary,
Header_name/binary>>/binary,
"', schema kind: "/utf8>>/binary,
Kind/binary>>/binary,
"). validate.validate_response_headers should have rejected this spec"/utf8>>/binary,
" before codegen ran. Please report this with the spec attached so the"/utf8>>/binary,
" validation gap can be fixed."/utf8>>.
-file("src/oaspec/internal/codegen/client_response.gleam", 347).
?DOC(false).
-spec classify_header_schema(
gleam@option:option(oaspec@openapi@schema:schema_ref()),
binary()
) -> header_field_type().
classify_header_schema(Schema_opt, Header_name) ->
case Schema_opt of
none ->
string_header;
{some, {inline, {string_schema, _, _, _, _, _, _}}} ->
string_header;
{some, {inline, {integer_schema, _, _, _, _, _, _, _}}} ->
int_header;
{some, {inline, {number_schema, _, _, _, _, _, _, _}}} ->
float_header;
{some, {inline, {boolean_schema, _}}} ->
bool_header;
{some, {reference, _, Name}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<<<"$ref to component schema '"/utf8, Name/binary>>/binary,
"'"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 358});
{some, {inline, {object_schema, _, _, _, _, _, _}}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<"inline object schema"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 363});
{some, {inline, {array_schema, _, _, _, _, _}}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<"inline array schema"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 365});
{some, {inline, {all_of_schema, _, _}}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<"allOf composition"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 367});
{some, {inline, {one_of_schema, _, _, _}}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<"oneOf composition"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 369});
{some, {inline, {any_of_schema, _, _, _}}} ->
erlang:error(#{gleam_error => panic,
message => unreachable_header_panic(
Header_name,
<<"anyOf composition"/utf8>>
),
file => <<?FILEPATH/utf8>>,
module => <<"oaspec/internal/codegen/client_response"/utf8>>,
function => <<"classify_header_schema"/utf8>>,
line => 371})
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 453).
?DOC(false).
-spec missing_required_error(binary(), binary()) -> binary().
missing_required_error(Header_name, Kind) ->
<<<<<<<<"InvalidResponse(detail: \"missing or invalid required "/utf8,
Kind/binary>>/binary,
" header: "/utf8>>/binary,
Header_name/binary>>/binary,
"\")"/utf8>>.
-file("src/oaspec/internal/codegen/client_response.gleam", 461).
?DOC(false).
-spec missing_required_error_inner(binary(), binary()) -> binary().
missing_required_error_inner(Header_name, Kind) ->
<<<<<<<<"InvalidResponse(detail: \"missing or invalid required "/utf8,
Kind/binary>>/binary,
" header: "/utf8>>/binary,
Header_name/binary>>/binary,
"\")"/utf8>>.
-file("src/oaspec/internal/codegen/client_response.gleam", 472).
?DOC(false).
-spec header_lookup_expr(binary()) -> binary().
header_lookup_expr(Header_name) ->
<<<<"list.key_find(resp.headers, \""/utf8,
(string:lowercase(Header_name))/binary>>/binary,
"\")"/utf8>>.
-file("src/oaspec/internal/codegen/client_response.gleam", 386).
?DOC(false).
-spec header_field_extraction(binary(), binary(), oaspec@openapi@spec:header()) -> binary().
header_field_extraction(Field_name, Header_name, Header) ->
Lookup = header_lookup_expr(Header_name),
Kind = classify_header_schema(erlang:element(4, Header), Header_name),
case {erlang:element(3, Header), Kind} of
{false, string_header} ->
<<<<<<<<"let "/utf8, Field_name/binary>>/binary, " = "/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.map(Some) |> result.unwrap(None)"/utf8>>;
{true, string_header} ->
<<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary,
" <- result.try("/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.map_error(fn(_) { "/utf8>>/binary,
(missing_required_error(Header_name, <<"string"/utf8>>))/binary>>/binary,
" }))"/utf8>>;
{false, int_header} ->
<<<<<<<<"let "/utf8, Field_name/binary>>/binary, " = "/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.try(int.parse) |> result.map(Some) |> result.unwrap(None)"/utf8>>;
{true, int_header} ->
<<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary,
" <- result.try("/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.try(int.parse) |> result.map_error(fn(_) { "/utf8>>/binary,
(missing_required_error(Header_name, <<"integer"/utf8>>))/binary>>/binary,
" }))"/utf8>>;
{false, float_header} ->
<<<<<<<<"let "/utf8, Field_name/binary>>/binary, " = "/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.try(float.parse) |> result.map(Some) |> result.unwrap(None)"/utf8>>;
{true, float_header} ->
<<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary,
" <- result.try("/utf8>>/binary,
Lookup/binary>>/binary,
" |> result.try(float.parse) |> result.map_error(fn(_) { "/utf8>>/binary,
(missing_required_error(Header_name, <<"number"/utf8>>))/binary>>/binary,
" }))"/utf8>>;
{false, bool_header} ->
<<<<<<<<"let "/utf8, Field_name/binary>>/binary, " = case "/utf8>>/binary,
Lookup/binary>>/binary,
" { Ok(\"true\") -> Some(True) Ok(\"false\") -> Some(False) _ -> None }"/utf8>>;
{true, bool_header} ->
<<<<<<<<<<<<"use "/utf8, Field_name/binary>>/binary,
" <- result.try(case "/utf8>>/binary,
Lookup/binary>>/binary,
" { Ok(\"true\") -> Ok(True) Ok(\"false\") -> Ok(False) _ -> Error("/utf8>>/binary,
(missing_required_error_inner(
Header_name,
<<"boolean"/utf8>>
))/binary>>/binary,
") })"/utf8>>
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 294).
?DOC(false).
-spec build_headers_record(
binary(),
oaspec@internal@util@http:http_status_code(),
oaspec@openapi@spec:response(oaspec@openapi@spec:resolved())
) -> gleam@option:option(headers_record()).
build_headers_record(Op_id, Status_code, Response) ->
Headers = begin
_pipe = erlang:element(4, Response),
_pipe@1 = maps:to_list(_pipe),
gleam@list:sort(
_pipe@1,
fun(A, B) ->
gleam@string:compare(erlang:element(1, A), erlang:element(1, B))
end
)
end,
case Headers of
[] ->
none;
_ ->
Record_name = <<<<<<<<"response_types."/utf8,
(oaspec@internal@util@naming:schema_to_type_name(
Op_id
))/binary>>/binary,
"Response"/utf8>>/binary,
(oaspec@internal@util@http:status_code_suffix(Status_code))/binary>>/binary,
"Headers"/utf8>>,
Fields = gleam@list:map(
Headers,
fun(Entry) ->
{Header_name, Header} = Entry,
Field_name = oaspec@internal@util@naming:to_snake_case(
Header_name
),
Pre_statement = header_field_extraction(
Field_name,
Header_name,
Header
),
{Field_name, Pre_statement}
end
),
Pre_statements = gleam@list:map(
Fields,
fun(P) -> erlang:element(2, P) end
),
Assignments = gleam@list:map(
Fields,
fun(P@1) ->
<<<<(erlang:element(1, P@1))/binary, ": "/utf8>>/binary,
(erlang:element(1, P@1))/binary>>
end
),
{some,
{headers_record,
Pre_statements,
<<<<<<Record_name/binary, "("/utf8>>/binary,
(gleam@string:join(Assignments, <<", "/utf8>>))/binary>>/binary,
")"/utf8>>}}
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 534).
?DOC(false).
-spec inline_schema_to_decoder(oaspec@openapi@schema:schema_object()) -> binary().
inline_schema_to_decoder(S) ->
case S of
{string_schema, _, _, _, _, _, _} ->
<<"dyn_decode.string"/utf8>>;
{integer_schema, _, _, _, _, _, _, _} ->
<<"dyn_decode.int"/utf8>>;
{number_schema, _, _, _, _, _, _, _} ->
<<"dyn_decode.float"/utf8>>;
{boolean_schema, _} ->
<<"dyn_decode.bool"/utf8>>;
_ ->
<<"dyn_decode.string"/utf8>>
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 482).
?DOC(false).
-spec get_response_decode_expr(
oaspec@openapi@schema:schema_ref(),
binary(),
oaspec@internal@util@http:http_status_code(),
oaspec@internal@codegen@context:context()
) -> binary().
get_response_decode_expr(Schema_ref, Op_id, Status_code, _) ->
case Schema_ref of
{reference, _, Name} ->
<<<<"decode.decode_"/utf8,
(oaspec@internal@util@naming:to_snake_case(Name))/binary>>/binary,
"(text)"/utf8>>;
{inline, {array_schema, _, Items, _, _, _}} ->
case Items of
{reference, _, Name@1} ->
<<<<"json.parse(text, dyn_decode.list(decode."/utf8,
(oaspec@internal@util@naming:to_snake_case(Name@1))/binary>>/binary,
"_decoder()))"/utf8>>;
{inline, Inner} ->
Inner_decoder = inline_schema_to_decoder(Inner),
<<<<"json.parse(text, dyn_decode.list("/utf8,
Inner_decoder/binary>>/binary,
"))"/utf8>>
end;
{inline, {string_schema, _, _, _, _, _, _}} ->
<<"json.parse(text, dyn_decode.string)"/utf8>>;
{inline, {integer_schema, _, _, _, _, _, _, _}} ->
<<"json.parse(text, dyn_decode.int)"/utf8>>;
{inline, {number_schema, _, _, _, _, _, _, _}} ->
<<"json.parse(text, dyn_decode.float)"/utf8>>;
{inline, {boolean_schema, _}} ->
<<"json.parse(text, dyn_decode.bool)"/utf8>>;
{inline, _} ->
Fn_name = <<<<<<"decode_"/utf8,
(oaspec@internal@util@naming:to_snake_case(Op_id))/binary>>/binary,
"_response_"/utf8>>/binary,
(oaspec@internal@util@naming:to_snake_case(
oaspec@internal@util@http:status_code_suffix(Status_code)
))/binary>>,
<<<<"decode."/utf8, Fn_name/binary>>/binary, "(text)"/utf8>>
end.
-file("src/oaspec/internal/codegen/client_response.gleam", 69).
?DOC(false).
-spec generate_single_content_response(
gleam@string_tree:string_tree(),
oaspec@internal@util@http:http_status_code(),
binary(),
binary(),
oaspec@openapi@spec:media_type(),
binary(),
oaspec@internal@codegen@context:context(),
gleam@option:option(headers_record())
) -> gleam@string_tree:string_tree().
generate_single_content_response(
Sb,
Status_code,
Variant_name,
Media_type_name,
Media_type,
Op_id,
Ctx,
Headers
) ->
case oaspec@internal@util@content_type:from_string(Media_type_name) of
application_octet_stream ->
case erlang:element(2, Media_type) of
{some, _} ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"bytes"/utf8>>,
Headers,
fun(Sb@1) ->
oaspec@internal@util@string_extra:indent(
Sb@1,
3,
<<"use bytes <- result.try(bytes_body(resp.body))"/utf8>>
)
end
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end;
wildcard ->
case erlang:element(2, Media_type) of
{some, _} ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"bytes"/utf8>>,
Headers,
fun(Sb@1) ->
oaspec@internal@util@string_extra:indent(
Sb@1,
3,
<<"use bytes <- result.try(bytes_body(resp.body))"/utf8>>
)
end
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end;
text_plain ->
case erlang:element(2, Media_type) of
{some, _} ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"text"/utf8>>,
Headers,
fun(Sb@2) ->
oaspec@internal@util@string_extra:indent(
Sb@2,
3,
<<"use text <- result.try(text_body(resp.body))"/utf8>>
)
end
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end;
application_xml ->
case erlang:element(2, Media_type) of
{some, _} ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"text"/utf8>>,
Headers,
fun(Sb@2) ->
oaspec@internal@util@string_extra:indent(
Sb@2,
3,
<<"use text <- result.try(text_body(resp.body))"/utf8>>
)
end
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end;
text_xml ->
case erlang:element(2, Media_type) of
{some, _} ->
body_branch(
Sb,
Status_code,
Variant_name,
<<"text"/utf8>>,
Headers,
fun(Sb@2) ->
oaspec@internal@util@string_extra:indent(
Sb@2,
3,
<<"use text <- result.try(text_body(resp.body))"/utf8>>
)
end
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end;
_ ->
case erlang:element(2, Media_type) of
{some, Schema_ref} ->
Decode_expr = get_response_decode_expr(
Schema_ref,
Op_id,
Status_code,
Ctx
),
Sb@3 = begin
_pipe = Sb,
_pipe@1 = oaspec@internal@util@string_extra:indent(
_pipe,
2,
<<(status_branch_pattern(Status_code))/binary,
" -> {"/utf8>>
),
_pipe@2 = oaspec@internal@util@string_extra:indent(
_pipe@1,
3,
<<"use text <- result.try(text_body(resp.body))"/utf8>>
),
emit_pre_statements(_pipe@2, Headers)
end,
_pipe@3 = Sb@3,
_pipe@4 = oaspec@internal@util@string_extra:indent(
_pipe@3,
3,
<<<<"case "/utf8, Decode_expr/binary>>/binary,
" {"/utf8>>
),
_pipe@5 = oaspec@internal@util@string_extra:indent(
_pipe@4,
4,
<<<<<<<<"Ok(decoded) -> Ok("/utf8, Variant_name/binary>>/binary,
"("/utf8>>/binary,
(prepend_default_status(
append_headers_arg(
<<"decoded"/utf8>>,
Headers
),
Status_code
))/binary>>/binary,
"))"/utf8>>
),
_pipe@6 = oaspec@internal@util@string_extra:indent(
_pipe@5,
4,
<<"Error(_) -> Error(DecodeFailure(detail: \"Failed to decode response body\"))"/utf8>>
),
_pipe@7 = oaspec@internal@util@string_extra:indent(
_pipe@6,
3,
<<"}"/utf8>>
),
oaspec@internal@util@string_extra:indent(
_pipe@7,
2,
<<"}"/utf8>>
);
_ ->
empty_body_branch(Sb, Status_code, Variant_name, Headers)
end
end.