refactor(config): create APIs for each root-name

This commit is contained in:
Shawn 2021-08-09 17:24:44 +08:00
parent bafcb7f34a
commit 74a849bfbb
1 changed files with 66 additions and 15 deletions

View File

@ -31,30 +31,35 @@
schema => #{type => string, default => <<".">>} schema => #{type => string, default => <<".">>}
}]). }]).
-define(TEXT_BODY(DESCR), #{ -define(TEXT_BODY(DESCR, SCHEMA), #{
description => list_to_binary(DESCR), description => list_to_binary(DESCR),
content => #{ content => #{
<<"text/plain">> => #{ <<"text/plain">> => #{
schema => #{} schema => SCHEMA
} }
} }
}). }).
-define(PREFIX, "/configs/").
-define(MAX_DEPTH, 1).
-define(ERR_MSG(MSG), io_lib:format("~p", [MSG])). -define(ERR_MSG(MSG), io_lib:format("~p", [MSG])).
api_spec() -> api_spec() ->
{config_apis(), []}. {config_apis(), []}.
config_apis() -> config_apis() ->
[config_api()]. [config_api(ConfPath, Schema) || {ConfPath, Schema} <-
get_conf_schema(emqx_config:get([]), ?MAX_DEPTH)].
config_api() -> config_api(ConfPath, Schema) ->
Path = path_join(ConfPath),
Metadata = #{ Metadata = #{
get => #{ get => #{
description => <<"Get configs">>, description => <<"Get configs">>,
parameters => ?PARAM_CONF_PATH,
responses => #{ responses => #{
<<"200">> => ?TEXT_BODY("Get configs successfully"), <<"200">> => ?TEXT_BODY("Get configs successfully", Schema),
<<"404">> => emqx_mgmt_util:response_error_schema( <<"404">> => emqx_mgmt_util:response_error_schema(
<<"Config not found">>, ['NOT_FOUND']) <<"Config not found">>, ['NOT_FOUND'])
} }
@ -70,22 +75,20 @@ config_api() ->
}, },
put => #{ put => #{
description => <<"Update configs for">>, description => <<"Update configs for">>,
parameters => ?PARAM_CONF_PATH, 'requestBody' => ?TEXT_BODY("The format of the request body is depend on the 'conf_path' parameter in the query string", Schema),
'requestBody' => ?TEXT_BODY("The format of the request body is depend on the 'conf_path' parameter in the query string"),
responses => #{ responses => #{
<<"200">> => ?TEXT_BODY("Update configs successfully"), <<"200">> => ?TEXT_BODY("Update configs successfully", Schema),
<<"400">> => emqx_mgmt_util:response_error_schema( <<"400">> => emqx_mgmt_util:response_error_schema(
<<"Update configs failed">>, ['UPDATE_FAILED']) <<"Update configs failed">>, ['UPDATE_FAILED'])
} }
} }
}, },
{"/configs", Metadata, config}. {?PREFIX ++ Path, Metadata, config}.
%%%============================================================================================== %%%==============================================================================================
%% parameters trans %% parameters trans
config(get, Req) -> config(get, Req) ->
%% TODO: query the config specified by the query string param 'conf_path' case emqx_config:find_raw(conf_path_from_http_path(Req)) of
case emqx_config:find_raw(conf_path_from_querystr(Req)) of
{ok, Conf} -> {ok, Conf} ->
{200, Conf}; {200, Conf};
{not_found, _, _} -> {not_found, _, _} ->
@ -93,15 +96,15 @@ config(get, Req) ->
end; end;
config(delete, Req) -> config(delete, Req) ->
%% TODO: remove the config specified by the query string param 'conf_path' %% remove the config specified by the query string param 'conf_path'
case emqx_config:remove(conf_path_from_querystr(Req)) of case emqx_config:remove(conf_path_from_http_path(Req) ++ conf_path_from_querystr(Req)) of
ok -> {200}; ok -> {200};
{error, Reason} -> {error, Reason} ->
{400, ?ERR_MSG(Reason)} {400, ?ERR_MSG(Reason)}
end; end;
config(put, Req) -> config(put, Req) ->
Path = [binary_to_atom(Key, latin1) || Key <- conf_path_from_querystr(Req)], Path = conf_path_from_http_path(Req),
ok = emqx_config:update(Path, http_body(Req)), ok = emqx_config:update(Path, http_body(Req)),
{200, emqx_config:get_raw(Path)}. {200, emqx_config:get_raw(Path)}.
@ -111,8 +114,56 @@ conf_path_from_querystr(Req) ->
Path -> string:lexemes(Path, ". ") Path -> string:lexemes(Path, ". ")
end. end.
conf_path_from_http_path(Req) ->
<<"/api/v5", ?PREFIX, Path/binary>> = cowboy_req:path(Req),
string:lexemes(Path, "/ ").
http_body(Req) -> http_body(Req) ->
{ok, Body, _} = cowboy_req:read_body(Req), {ok, Body, _} = cowboy_req:read_body(Req),
try jsx:decode(Body, [{return_maps, true}]) try jsx:decode(Body, [{return_maps, true}])
catch error:badarg -> Body catch error:badarg -> Body
end. end.
get_conf_schema(Conf, MaxDepth) ->
get_conf_schema([], maps:to_list(Conf), [], MaxDepth).
get_conf_schema(_BasePath, [], Result, _MaxDepth) ->
Result;
get_conf_schema(BasePath, [{Key, Conf} | Confs], Result, MaxDepth) ->
Path = BasePath ++ [Key],
Depth = length(Path),
Result1 = case is_map(Conf) of
true when Depth < MaxDepth ->
get_conf_schema(Path, maps:to_list(Conf), Result, MaxDepth);
true when Depth >= MaxDepth -> Result;
false -> Result
end,
get_conf_schema(BasePath, Confs, [{Path, gen_schema(Conf)} | Result1], MaxDepth).
%% TODO: generate from hocon schema
gen_schema(Conf) when is_boolean(Conf) ->
#{type => boolean};
gen_schema(Conf) when is_binary(Conf); is_atom(Conf) ->
#{type => string};
gen_schema(Conf) when is_number(Conf) ->
#{type => number};
gen_schema(Conf) when is_list(Conf) ->
#{type => array, items => case Conf of
[] -> #{}; %% don't know the type
_ -> gen_schema(hd(Conf))
end};
gen_schema(Conf) when is_map(Conf) ->
#{type => object, properties =>
maps:map(fun(_K, V) -> gen_schema(V) end, Conf)};
gen_schema(_Conf) ->
%% the conf is not of JSON supported type, it may have been converted
%% by the hocon schema
#{type => string}.
path_join([P]) -> str(P);
path_join([P | Path]) ->
str(P) ++ "/" ++ path_join(Path).
str(S) when is_list(S) -> S;
str(S) when is_binary(S) -> binary_to_list(S);
str(S) when is_atom(S) -> atom_to_list(S).