emqx_dashboard_schema_api.erl 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. %% This module is for dashboard to retrieve the schema of
  17. %% 1. hot-config
  18. %% 2. bridge
  19. %% 3. bridge_v2
  20. %% 4. connector
  21. -module(emqx_dashboard_schema_api).
  22. -behaviour(minirest_api).
  23. -include_lib("hocon/include/hoconsc.hrl").
  24. %% minirest API
  25. -export([api_spec/0, paths/0, schema/1]).
  26. -export([get_schema/2]).
  27. %% for test
  28. -export([bridge_schema_json/0]).
  29. -define(TAGS, [<<"dashboard">>]).
  30. -define(BAD_REQUEST, 'BAD_REQUEST').
  31. -define(TO_REF(_N_, _F_), iolist_to_binary([to_bin(_N_), ".", to_bin(_F_)])).
  32. -define(TO_COMPONENTS_SCHEMA(_M_, _F_),
  33. iolist_to_binary([
  34. <<"#/components/schemas/">>,
  35. ?TO_REF(emqx_dashboard_swagger:namespace(_M_), _F_)
  36. ])
  37. ).
  38. -define(SCHEMA_VERSION, <<"0.2.0">>).
  39. %%--------------------------------------------------------------------
  40. %% minirest API and schema
  41. %%--------------------------------------------------------------------
  42. api_spec() ->
  43. emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
  44. paths() ->
  45. ["/schemas/:name"].
  46. %% This is a rather hidden API, so we don't need to add translations for the description.
  47. %% TODO(5.7): delete 'bridges'
  48. schema("/schemas/:name") ->
  49. Schemas = [hotconf, bridges, actions, connectors],
  50. #{
  51. 'operationId' => get_schema,
  52. get => #{
  53. parameters => [
  54. {name, hoconsc:mk(hoconsc:enum(Schemas), #{in => path})}
  55. ],
  56. desc => <<
  57. "Get the schema JSON of the specified name. "
  58. "NOTE: only intended for EMQX Dashboard."
  59. >>,
  60. tags => ?TAGS,
  61. security => [],
  62. responses => #{
  63. 200 => hoconsc:mk(binary(), #{desc => <<"The JSON schema of the specified name.">>})
  64. }
  65. }
  66. }.
  67. %%--------------------------------------------------------------------
  68. %% API Handler funcs
  69. %%--------------------------------------------------------------------
  70. get_schema(get, #{
  71. bindings := #{name := Name}
  72. }) ->
  73. {200, gen_schema(Name)};
  74. get_schema(get, _) ->
  75. {400, ?BAD_REQUEST, <<"unknown">>}.
  76. gen_schema(hotconf) ->
  77. hotconf_schema_json();
  78. gen_schema(bridges) ->
  79. bridge_schema_json();
  80. gen_schema(actions) ->
  81. actions_schema_json();
  82. gen_schema(connectors) ->
  83. connectors_schema_json().
  84. hotconf_schema_json() ->
  85. SchemaInfo = #{
  86. title => <<"Hot Conf Schema">>,
  87. version => ?SCHEMA_VERSION
  88. },
  89. gen_api_schema_json_iodata(emqx_mgmt_api_configs, SchemaInfo).
  90. bridge_schema_json() ->
  91. SchemaInfo = #{
  92. title => <<"Data Bridge Schema">>,
  93. version => ?SCHEMA_VERSION
  94. },
  95. gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo).
  96. actions_schema_json() ->
  97. SchemaInfo = #{
  98. title => <<"Actions and Sources Schema">>,
  99. version => ?SCHEMA_VERSION
  100. },
  101. gen_api_schema_json_iodata(emqx_bridge_v2_api, SchemaInfo).
  102. connectors_schema_json() ->
  103. SchemaInfo = #{
  104. title => <<"Connectors Schema">>,
  105. version => ?SCHEMA_VERSION
  106. },
  107. gen_api_schema_json_iodata(emqx_connector_api, SchemaInfo).
  108. gen_api_schema_json_iodata(SchemaMod, SchemaInfo) ->
  109. emqx_dashboard_swagger:gen_api_schema_json_iodata(
  110. SchemaMod,
  111. SchemaInfo,
  112. fun hocon_schema_to_spec/2
  113. ).
  114. hocon_schema_to_spec(?R_REF(Module, StructName), _LocalModule) ->
  115. {#{<<"$ref">> => ?TO_COMPONENTS_SCHEMA(Module, StructName)}, [{Module, StructName}]};
  116. hocon_schema_to_spec(?REF(StructName), LocalModule) ->
  117. {#{<<"$ref">> => ?TO_COMPONENTS_SCHEMA(LocalModule, StructName)}, [{LocalModule, StructName}]};
  118. hocon_schema_to_spec(Type, LocalModule) when ?IS_TYPEREFL(Type) ->
  119. {typename_to_spec(typerefl:name(Type), LocalModule), []};
  120. hocon_schema_to_spec(?ARRAY(Item), LocalModule) ->
  121. {Schema, Refs} = hocon_schema_to_spec(Item, LocalModule),
  122. {#{type => array, items => Schema}, Refs};
  123. hocon_schema_to_spec(?ENUM(Items), _LocalModule) ->
  124. {#{type => enum, symbols => Items}, []};
  125. hocon_schema_to_spec(?MAP(Name, Type), LocalModule) ->
  126. {Schema, SubRefs} = hocon_schema_to_spec(Type, LocalModule),
  127. {
  128. #{
  129. <<"type">> => object,
  130. <<"properties">> => #{<<"$", (to_bin(Name))/binary>> => Schema}
  131. },
  132. SubRefs
  133. };
  134. hocon_schema_to_spec(?UNION(Types, _DisplayName), LocalModule) ->
  135. {OneOf, Refs} = lists:foldl(
  136. fun(Type, {Acc, RefsAcc}) ->
  137. {Schema, SubRefs} = hocon_schema_to_spec(Type, LocalModule),
  138. {[Schema | Acc], SubRefs ++ RefsAcc}
  139. end,
  140. {[], []},
  141. hoconsc:union_members(Types)
  142. ),
  143. {#{<<"oneOf">> => OneOf}, Refs};
  144. hocon_schema_to_spec(Atom, _LocalModule) when is_atom(Atom) ->
  145. {#{type => enum, symbols => [Atom]}, []}.
  146. typename_to_spec(TypeStr, Module) ->
  147. emqx_conf_schema_types:readable_dashboard(Module, TypeStr).
  148. to_bin(List) when is_list(List) -> iolist_to_binary(List);
  149. to_bin(Boolean) when is_boolean(Boolean) -> Boolean;
  150. to_bin(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8);
  151. to_bin(X) -> X.