fix(bridge-v2): report descriptive error on invalid update request
Before this commit, generic validation errors were reported as union mismatches of _all_ of the bridge schemas. After this commit, specific schema is chosen before validation.
This commit is contained in:
parent
b2f5e50f16
commit
5c2a68076f
|
@ -96,7 +96,7 @@
|
|||
namespace() -> "actions_and_sources".
|
||||
|
||||
api_spec() ->
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => fun check_api_schema/2}).
|
||||
|
||||
paths() ->
|
||||
[
|
||||
|
@ -656,6 +656,23 @@ schema("/source_types") ->
|
|||
}
|
||||
}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
check_api_schema(Request, ReqMeta = #{path := Path = "/actions/:id", method := put}) ->
|
||||
Spec = maps:get(put, schema(Path)),
|
||||
BridgeId = emqx_utils_maps:deep_get([bindings, id], Request),
|
||||
try emqx_bridge_resource:parse_bridge_id(BridgeId, #{atom_name => false}) of
|
||||
{BridgeType, _Name} ->
|
||||
Schema = emqx_bridge_v2_schema:action_api_schema("put", BridgeType),
|
||||
SpecRefined = Spec#{'requestBody' => Schema},
|
||||
emqx_dashboard_swagger:filter_check_request(Request, ReqMeta#{apispec => SpecRefined})
|
||||
catch
|
||||
throw:#{reason := Reason} ->
|
||||
?NOT_FOUND(<<"Invalid bridge ID, ", Reason/binary>>)
|
||||
end;
|
||||
check_api_schema(Request, ReqMeta) ->
|
||||
emqx_dashboard_swagger:filter_check_request(Request, ReqMeta).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Thin Handlers
|
||||
%%------------------------------------------------------------------------------
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
actions_get_response/0,
|
||||
actions_put_request/0,
|
||||
actions_post_request/0,
|
||||
action_api_schema/2,
|
||||
actions_examples/1,
|
||||
action_values/4
|
||||
]).
|
||||
|
@ -100,6 +101,15 @@ actions_api_schema(Method) ->
|
|||
APISchemas = ?MODULE:registered_actions_api_schemas(Method),
|
||||
hoconsc:union(bridge_api_union(APISchemas)).
|
||||
|
||||
action_api_schema(Method, BridgeV2Type) ->
|
||||
APISchemas = ?MODULE:registered_actions_api_schemas(Method),
|
||||
case lists:keyfind(atom_to_binary(BridgeV2Type), 1, APISchemas) of
|
||||
{_, SchemaRef} ->
|
||||
hoconsc:mk(SchemaRef);
|
||||
false ->
|
||||
unknown_bridge_schema(BridgeV2Type)
|
||||
end.
|
||||
|
||||
registered_actions_api_schemas(Method) ->
|
||||
RegisteredSchemas = emqx_action_info:registered_schema_modules_actions(),
|
||||
[
|
||||
|
@ -231,6 +241,17 @@ bridge_api_union(Refs) ->
|
|||
end
|
||||
end.
|
||||
|
||||
-dialyzer({nowarn_function, [unknown_bridge_schema/1]}).
|
||||
unknown_bridge_schema(BridgeV2Type) ->
|
||||
hoconsc:mk(typerefl:any(), #{
|
||||
validator => fun(_) ->
|
||||
throw(#{
|
||||
value => BridgeV2Type,
|
||||
reason => <<"unknown bridge type">>
|
||||
})
|
||||
end
|
||||
}).
|
||||
|
||||
-spec method_values(action | source, http_method(), atom()) -> schema_example_map().
|
||||
method_values(Kind, post, Type) ->
|
||||
KindBin = atom_to_binary(Kind),
|
||||
|
|
|
@ -156,12 +156,15 @@ t_create_via_http(Config) ->
|
|||
t_on_get_status(Config) ->
|
||||
emqx_bridge_v2_testlib:t_on_get_status(Config, #{}).
|
||||
|
||||
t_invalid_config(Config) ->
|
||||
t_create_invalid_config(Config) ->
|
||||
?assertMatch(
|
||||
{error,
|
||||
{_Status, _, #{
|
||||
<<"code">> := <<"BAD_REQUEST">>,
|
||||
<<"message">> := #{<<"kind">> := <<"validation_error">>}
|
||||
<<"message">> := #{
|
||||
<<"kind">> := <<"validation_error">>,
|
||||
<<"reason">> := <<"Inconsistent 'min_part_size'", _/bytes>>
|
||||
}
|
||||
}}},
|
||||
emqx_bridge_v2_testlib:create_bridge_api(
|
||||
Config,
|
||||
|
@ -174,6 +177,28 @@ t_invalid_config(Config) ->
|
|||
)
|
||||
).
|
||||
|
||||
t_update_invalid_config(Config) ->
|
||||
?assertMatch({ok, _Bridge}, emqx_bridge_v2_testlib:create_bridge(Config)),
|
||||
?assertMatch(
|
||||
{error,
|
||||
{_Status, _, #{
|
||||
<<"code">> := <<"BAD_REQUEST">>,
|
||||
<<"message">> := #{
|
||||
<<"kind">> := <<"validation_error">>,
|
||||
<<"reason">> := <<"Inconsistent 'min_part_size'", _/bytes>>
|
||||
}
|
||||
}}},
|
||||
emqx_bridge_v2_testlib:update_bridge_api(
|
||||
Config,
|
||||
_Overrides = #{
|
||||
<<"parameters">> => #{
|
||||
<<"min_part_size">> => <<"5GB">>,
|
||||
<<"max_part_size">> => <<"100MB">>
|
||||
}
|
||||
}
|
||||
)
|
||||
).
|
||||
|
||||
t_aggreg_upload(Config) ->
|
||||
Bucket = ?config(s3_bucket, Config),
|
||||
BridgeName = ?config(bridge_name, Config),
|
||||
|
|
|
@ -335,8 +335,8 @@ filter_check_request_and_translate_body(Request, RequestMeta) ->
|
|||
filter_check_request(Request, RequestMeta) ->
|
||||
translate_req(Request, RequestMeta, fun check_only/3).
|
||||
|
||||
translate_req(Request, #{module := Module, path := Path, method := Method}, CheckFun) ->
|
||||
#{Method := Spec} = apply(Module, schema, [Path]),
|
||||
translate_req(Request, ReqMeta = #{module := Module}, CheckFun) ->
|
||||
Spec = find_req_apispec(ReqMeta),
|
||||
try
|
||||
Params = maps:get(parameters, Spec, []),
|
||||
Body = maps:get('requestBody', Spec, []),
|
||||
|
@ -349,6 +349,12 @@ translate_req(Request, #{module := Module, path := Path, method := Method}, Chec
|
|||
{400, 'BAD_REQUEST', Msg}
|
||||
end.
|
||||
|
||||
find_req_apispec(#{apispec := Spec}) ->
|
||||
Spec;
|
||||
find_req_apispec(#{module := Module, path := Path, method := Method}) ->
|
||||
#{Method := Spec} = apply(Module, schema, [Path]),
|
||||
Spec.
|
||||
|
||||
check_and_translate(Schema, Map, Opts) ->
|
||||
hocon_tconf:check_plain(Schema, Map, Opts).
|
||||
|
||||
|
|
Loading…
Reference in New Issue