%%-------------------------------------------------------------------- %% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %%-------------------------------------------------------------------- -module(emqx_mgmt_api_routes). -include_lib("emqx/include/emqx.hrl"). %% API -behaviour(minirest_api). -export([api_spec/0]). -export([ routes/2 , route/2]). -export([query/4]). -define(TOPIC_NOT_FOUND, 'TOPIC_NOT_FOUND'). -define(ROUTES_QS_SCHEMA, [{<<"topic">>, binary}, {<<"node">>, atom}]). -import(emqx_mgmt_util, [ object_schema/2 , object_array_schema/2 , error_schema/2 , properties/1 , page_params/0 , generate_response/1 ]). api_spec() -> {[routes_api(), route_api()], []}. properties() -> properties([ {topic, string}, {node, string} ]). routes_api() -> Metadata = #{ get => #{ description => <<"EMQ X routes">>, parameters => [topic_param(query) , node_param()] ++ page_params(), responses => #{ <<"200">> => object_array_schema(properties(), <<"List route info">>), <<"400">> => error_schema(<<"Invalid parameters">>, ['INVALID_PARAMETER']) } } }, {"/routes", Metadata, routes}. route_api() -> Metadata = #{ get => #{ description => <<"EMQ X routes">>, parameters => [topic_param(path)], responses => #{ <<"200">> => object_schema(properties(), <<"Route info">>), <<"404">> => error_schema(<<"Topic not found">>, [?TOPIC_NOT_FOUND]) } } }, {"/routes/:topic", Metadata, route}. %%%============================================================================================== %% parameters trans routes(get, #{query_string := Qs}) -> list(generate_topic(Qs)). route(get, #{bindings := Bindings}) -> lookup(generate_topic(Bindings)). %%%============================================================================================== %% api apply list(Params) -> Response = emqx_mgmt_api:node_query(node(), Params, emqx_route, ?ROUTES_QS_SCHEMA, {?MODULE, query}), generate_response(Response). lookup(#{topic := Topic}) -> case emqx_mgmt:lookup_routes(Topic) of [] -> {404, #{code => ?TOPIC_NOT_FOUND, message => <<"Topic not found">>}}; [Route] -> {200, format(Route)} end. %%%============================================================================================== %% internal generate_topic(Params = #{<<"topic">> := Topic}) -> Params#{<<"topic">> => uri_string:percent_decode(Topic)}; generate_topic(Params = #{topic := Topic}) -> Params#{topic => uri_string:percent_decode(Topic)}; generate_topic(Params) -> Params. query(Tab, {Qs, _}, Continuation, Limit) -> Ms = qs2ms(Qs, [{{route, '_', '_'}, [], ['$_']}]), emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit, fun format/1). qs2ms([], Res) -> Res; qs2ms([{topic,'=:=', T} | Qs], [{{route, _, N}, [], ['$_']}]) -> qs2ms(Qs, [{{route, T, N}, [], ['$_']}]); qs2ms([{node,'=:=', N} | Qs], [{{route, T, _}, [], ['$_']}]) -> qs2ms(Qs, [{{route, T, N}, [], ['$_']}]). format(#route{topic = Topic, dest = {_, Node}}) -> #{topic => Topic, node => Node}; format(#route{topic = Topic, dest = Node}) -> #{topic => Topic, node => Node}. topic_param(In) -> #{ name => topic, in => In, required => In == path, description => <<"Topic string, url encoding">>, schema => #{type => string} }. node_param()-> #{ name => node, in => query, required => false, description => <<"Node">>, schema => #{type => string} }.