From 74a849bfbb25fa0b3b623b95c86f05e741159b09 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Mon, 9 Aug 2021 17:24:44 +0800 Subject: [PATCH] refactor(config): create APIs for each root-name --- .../src/emqx_mgmt_api_configs.erl | 81 +++++++++++++++---- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_api_configs.erl b/apps/emqx_management/src/emqx_mgmt_api_configs.erl index b69593747..aec32bdf0 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_configs.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_configs.erl @@ -31,30 +31,35 @@ schema => #{type => string, default => <<".">>} }]). --define(TEXT_BODY(DESCR), #{ +-define(TEXT_BODY(DESCR, SCHEMA), #{ description => list_to_binary(DESCR), content => #{ <<"text/plain">> => #{ - schema => #{} + schema => SCHEMA } } }). +-define(PREFIX, "/configs/"). + +-define(MAX_DEPTH, 1). + -define(ERR_MSG(MSG), io_lib:format("~p", [MSG])). api_spec() -> {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 = #{ get => #{ description => <<"Get configs">>, - parameters => ?PARAM_CONF_PATH, responses => #{ - <<"200">> => ?TEXT_BODY("Get configs successfully"), + <<"200">> => ?TEXT_BODY("Get configs successfully", Schema), <<"404">> => emqx_mgmt_util:response_error_schema( <<"Config not found">>, ['NOT_FOUND']) } @@ -70,22 +75,20 @@ config_api() -> }, put => #{ 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"), + 'requestBody' => ?TEXT_BODY("The format of the request body is depend on the 'conf_path' parameter in the query string", Schema), responses => #{ - <<"200">> => ?TEXT_BODY("Update configs successfully"), + <<"200">> => ?TEXT_BODY("Update configs successfully", Schema), <<"400">> => emqx_mgmt_util:response_error_schema( <<"Update configs failed">>, ['UPDATE_FAILED']) } } }, - {"/configs", Metadata, config}. + {?PREFIX ++ Path, Metadata, config}. %%%============================================================================================== %% parameters trans config(get, Req) -> - %% TODO: query the config specified by the query string param 'conf_path' - case emqx_config:find_raw(conf_path_from_querystr(Req)) of + case emqx_config:find_raw(conf_path_from_http_path(Req)) of {ok, Conf} -> {200, Conf}; {not_found, _, _} -> @@ -93,15 +96,15 @@ config(get, Req) -> end; config(delete, Req) -> - %% TODO: remove the config specified by the query string param 'conf_path' - case emqx_config:remove(conf_path_from_querystr(Req)) of + %% remove the config specified by the query string param 'conf_path' + case emqx_config:remove(conf_path_from_http_path(Req) ++ conf_path_from_querystr(Req)) of ok -> {200}; {error, Reason} -> {400, ?ERR_MSG(Reason)} end; 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)), {200, emqx_config:get_raw(Path)}. @@ -111,8 +114,56 @@ conf_path_from_querystr(Req) -> Path -> string:lexemes(Path, ". ") end. +conf_path_from_http_path(Req) -> + <<"/api/v5", ?PREFIX, Path/binary>> = cowboy_req:path(Req), + string:lexemes(Path, "/ "). + http_body(Req) -> {ok, Body, _} = cowboy_req:read_body(Req), try jsx:decode(Body, [{return_maps, true}]) catch error:badarg -> Body 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).