Просмотр исходного кода

Merge pull request #7624 from DDDHuang/fix_api_params

Fix api params
Xinyu Liu 3 лет назад
Родитель
Сommit
21fe7f01ee
29 измененных файлов с 130 добавлено и 166 удалено
  1. 0 1
      apps/emqx/rebar.config
  2. 10 6
      apps/emqx_authn/src/emqx_authn_api.erl
  3. 1 1
      apps/emqx_connector/src/emqx_connector_http.erl
  4. 7 8
      apps/emqx_connector/src/emqx_connector_mongo.erl
  5. 2 2
      apps/emqx_connector/src/emqx_connector_schema_lib.erl
  6. 1 1
      apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl
  7. 1 4
      apps/emqx_dashboard/rebar.config
  8. 1 1
      apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl
  9. 3 1
      apps/emqx_dashboard/src/emqx_dashboard_swagger.erl
  10. 1 1
      apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl
  11. 1 1
      apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl
  12. 1 1
      apps/emqx_exhook/src/emqx_exhook_schema.erl
  13. 4 4
      apps/emqx_gateway/src/emqx_gateway_api.erl
  14. 2 2
      apps/emqx_gateway/src/emqx_gateway_api_authn.erl
  15. 12 12
      apps/emqx_gateway/src/emqx_gateway_api_clients.erl
  16. 8 6
      apps/emqx_gateway/src/emqx_gateway_api_listeners.erl
  17. 5 5
      apps/emqx_gateway/src/emqx_gateway_schema.erl
  18. 1 1
      apps/emqx_management/src/emqx_mgmt_api_metrics.erl
  19. 25 66
      apps/emqx_management/src/emqx_mgmt_api_stats.erl
  20. 6 6
      apps/emqx_modules/src/emqx_delayed_api.erl
  21. 6 4
      apps/emqx_plugin_libs/src/emqx_plugin_libs_metrics.erl
  22. 11 11
      apps/emqx_rule_engine/src/emqx_rule_api_schema.erl
  23. 8 8
      apps/emqx_rule_engine/src/emqx_rule_engine_api.erl
  24. 7 7
      apps/emqx_rule_engine/src/emqx_rule_runtime.erl
  25. 2 2
      apps/emqx_slow_subs/src/emqx_slow_subs_api.erl
  26. 1 1
      apps/emqx_slow_subs/src/emqx_slow_subs_schema.erl
  27. 1 1
      apps/emqx_slow_subs/test/emqx_slow_subs_api_SUITE.erl
  28. 1 1
      mix.exs
  29. 1 1
      rebar.config

+ 0 - 1
apps/emqx/rebar.config

@@ -24,7 +24,6 @@
 {deps, [
     {lc, {git, "https://github.com/emqx/lc.git", {tag, "0.2.1"}}},
     {gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}},
-    {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.8.6"}}},
     {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}},
     {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.9.0"}}},
     {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.9.1"}}},

+ 10 - 6
apps/emqx_authn/src/emqx_authn_api.erl

@@ -149,8 +149,8 @@ fields(response_users) ->
     paginated_list_type(ref(response_user));
 fields(pagination_meta) ->
     [
-        {page, non_neg_integer()},
-        {limit, non_neg_integer()},
+        {page, pos_integer()},
+        {limit, pos_integer()},
         {count, non_neg_integer()}
     ].
 
@@ -431,8 +431,10 @@ schema("/authentication/:id/users") ->
             description => <<"List users in authenticator in global authentication chain">>,
             parameters => [
                 param_auth_id(),
-                {page, mk(integer(), #{in => query, desc => <<"Page Index">>, required => false})},
-                {limit, mk(integer(), #{in => query, desc => <<"Page Limit">>, required => false})},
+                {page,
+                    mk(pos_integer(), #{in => query, desc => <<"Page Index">>, required => false})},
+                {limit,
+                    mk(pos_integer(), #{in => query, desc => <<"Page Limit">>, required => false})},
                 {like_username,
                     mk(binary(), #{
                         in => query,
@@ -481,8 +483,10 @@ schema("/listeners/:listener_id/authentication/:id/users") ->
             parameters => [
                 param_listener_id(),
                 param_auth_id(),
-                {page, mk(integer(), #{in => query, desc => <<"Page Index">>, required => false})},
-                {limit, mk(integer(), #{in => query, desc => <<"Page Limit">>, required => false})}
+                {page,
+                    mk(pos_integer(), #{in => query, desc => <<"Page Index">>, required => false})},
+                {limit,
+                    mk(pos_integer(), #{in => query, desc => <<"Page Limit">>, required => false})}
             ],
             responses => #{
                 200 => emqx_dashboard_swagger:schema_with_example(

+ 1 - 1
apps/emqx_connector/src/emqx_connector_http.erl

@@ -95,7 +95,7 @@ For example: `http://localhost:9901/`
             , desc => "The type of the pool. Can be one of `random`, `hash`."
             })}
     , {pool_size,
-        sc(non_neg_integer(),
+        sc(pos_integer(),
            #{ default => 8
             , desc => "The pool size."
             })}

+ 7 - 8
apps/emqx_connector/src/emqx_connector_mongo.erl

@@ -76,8 +76,8 @@ fields(sharded) ->
     , {w_mode, fun w_mode/1}
     ] ++ mongo_fields();
 fields(topology) ->
-    [ {pool_size, fun internal_pool_size/1}
-    , {max_overflow, fun emqx_connector_schema_lib:pool_size/1}
+    [ {pool_size, fun emqx_connector_schema_lib:pool_size/1}
+    , {max_overflow, fun max_overflow/1}
     , {overflow_ttl, fun duration/1}
     , {overflow_check_period, fun duration/1}
     , {local_threshold_ms, fun duration/1}
@@ -114,12 +114,6 @@ mongo_fields() ->
     ] ++
     emqx_connector_schema_lib:ssl_fields().
 
-internal_pool_size(type) -> integer();
-internal_pool_size(desc) -> "Pool size on start.";
-internal_pool_size(default) -> 1;
-internal_pool_size(validator) -> [?MIN(1)];
-internal_pool_size(_) -> undefined.
-
 %% ===================================================================
 
 on_start(InstId, Config = #{mongo_type := Type,
@@ -334,6 +328,11 @@ duration(desc) -> "Time interval, such as timeout or TTL.";
 duration(required) -> false;
 duration(_) -> undefined.
 
+max_overflow(type) -> non_neg_integer();
+max_overflow(desc) -> "Max Overflow.";
+max_overflow(default) -> 0;
+max_overflow(_) -> undefined.
+
 replica_set_name(type) -> binary();
 replica_set_name(desc) -> "Name of the replica set.";
 replica_set_name(required) -> false;

+ 2 - 2
apps/emqx_connector/src/emqx_connector_schema_lib.erl

@@ -34,7 +34,7 @@
         ]).
 
 -type database() :: binary().
--type pool_size() :: integer().
+-type pool_size() :: pos_integer().
 -type username() :: binary().
 -type password() :: binary().
 
@@ -72,7 +72,7 @@ database(required) -> true;
 database(validator) -> [?NOT_EMPTY("the value of the field 'database' cannot be empty")];
 database(_) -> undefined.
 
-pool_size(type) -> integer();
+pool_size(type) -> pos_integer();
 pool_size(desc) -> "Size of the connection pool.";
 pool_size(default) -> 8;
 pool_size(validator) -> [?MIN(1)];

+ 1 - 1
apps/emqx_connector/src/mqtt/emqx_connector_mqtt_schema.erl

@@ -93,7 +93,7 @@ topic filters for 'remote_topic' of ingress connections.
         "messages in case of ACK not received.",
         #{default => "15s"})}
     , {max_inflight,
-        sc(integer(),
+        sc(non_neg_integer(),
            #{ default => 32
             , desc => "Max inflight (sent, but un-acked) messages of the MQTT protocol"
             })}

+ 1 - 4
apps/emqx_dashboard/rebar.config

@@ -1,9 +1,6 @@
 %% -*- mode: erlang -*-
 
-{deps,
- [ {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.8.6"}}}
- , {emqx, {path, "../emqx"}}
- ]}.
+{deps, [{emqx, {path, "../emqx"}}]}.
 
 {edoc_opts, [{preprocess, true}]}.
 {erl_opts, [warn_unused_vars,

+ 1 - 1
apps/emqx_dashboard/src/emqx_dashboard_monitor_api.erl

@@ -107,7 +107,7 @@ fields(sampler) ->
     Samplers =
         [{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
         || SamplerName <- ?SAMPLER_LIST],
-    [{time_stamp, hoconsc:mk(integer(), #{desc => <<"Timestamp">>})} | Samplers];
+    [{time_stamp, hoconsc:mk(non_neg_integer(), #{desc => <<"Timestamp">>})} | Samplers];
 
 fields(sampler_current) ->
     [{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}

+ 3 - 1
apps/emqx_dashboard/src/emqx_dashboard_swagger.erl

@@ -127,7 +127,7 @@ namespace() -> "public".
 fields(page) ->
     Desc = <<"Page number of the results to fetch.">>,
     Meta = #{in => query, desc => Desc, default => 1, example => 1},
-    [{page, hoconsc:mk(integer(), Meta)}];
+    [{page, hoconsc:mk(pos_integer(), Meta)}];
 fields(limit) ->
     Desc = iolist_to_binary([
         <<"Results per page(max ">>,
@@ -582,6 +582,8 @@ typename_to_spec("float()", _Mod) ->
 typename_to_spec("integer()", _Mod) ->
     #{type => integer, example => 100};
 typename_to_spec("non_neg_integer()", _Mod) ->
+    #{type => integer, minimum => 0, example => 100};
+typename_to_spec("pos_integer()", _Mod) ->
     #{type => integer, minimum => 1, example => 100};
 typename_to_spec("number()", _Mod) ->
     #{type => number, example => 42};

+ 1 - 1
apps/emqx_dashboard/test/emqx_swagger_parameter_SUITE.erl

@@ -101,7 +101,7 @@ t_public_ref(_Config) ->
                 minimum => 1,type => integer}}},
         #{<<"public.page">> => #{description => <<"Page number of the results to fetch.">>,
             example => 1,in => query,name => page,
-            schema => #{default => 1,example => 100,type => integer}}}],
+            schema => #{default => 1,example => 100,minimum => 1,type => integer}}}],
     ?assertEqual(ExpectRefs, emqx_dashboard_swagger:components(Refs,#{})),
     ok.
 

+ 1 - 1
apps/emqx_dashboard/test/emqx_swagger_response_SUITE.erl

@@ -185,7 +185,7 @@ t_complicated_type(_Config) ->
     Object = #{<<"content">> => #{<<"application/json">> =>
     #{<<"schema">> => #{<<"properties">> =>
     [
-        {<<"no_neg_integer">>, #{example => 100, minimum => 1, type => integer}},
+        {<<"no_neg_integer">>, #{example => 100, minimum => 0, type => integer}},
         {<<"url">>, #{example => <<"http://127.0.0.1">>, type => string}},
         {<<"server">>, #{example => <<"127.0.0.1:80">>, type => string}},
         {<<"connect_timeout">>, #{example => infinity, <<"oneOf">> => [

+ 1 - 1
apps/emqx_exhook/src/emqx_exhook_schema.erl

@@ -92,7 +92,7 @@ fields(server) ->
             )},
         {pool_size,
             sc(
-                integer(),
+                pos_integer(),
                 #{
                     default => 8,
                     example => 8,

+ 4 - 4
apps/emqx_gateway/src/emqx_gateway_api.erl

@@ -284,12 +284,12 @@ fields(gateway_overview) ->
             )},
         {max_connections,
             mk(
-                integer(),
+                pos_integer(),
                 #{desc => <<"The Gateway allowed maximum connections/clients">>}
             )},
         {current_connections,
             mk(
-                integer(),
+                non_neg_integer(),
                 #{desc => <<"The Gateway current connected connections/clients">>}
             )},
         {listeners,
@@ -410,11 +410,11 @@ convert_listener_struct(Schema) ->
     ),
     lists:keystore(listeners, 1, Schema1, {listeners, ListenerSchema}).
 
-remove_listener_and_authn(Schmea) ->
+remove_listener_and_authn(Schema) ->
     lists:keydelete(
         authentication,
         1,
-        lists:keydelete(listeners, 1, Schmea)
+        lists:keydelete(listeners, 1, Schema)
     ).
 
 listeners_schema(?R_REF(_Mod, tcp_listeners)) ->

+ 2 - 2
apps/emqx_gateway/src/emqx_gateway_api_authn.erl

@@ -384,7 +384,7 @@ params_paging_in_qs() ->
     [
         {page,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     required => false,
@@ -394,7 +394,7 @@ params_paging_in_qs() ->
             )},
         {limit,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     required => false,

+ 12 - 12
apps/emqx_gateway/src/emqx_gateway_api_clients.erl

@@ -392,21 +392,21 @@ format_channel_info({_, Infos, Stats} = R) ->
         {heap_size, Stats, 0},
         {reductions, Stats, 0}
     ],
-    eval(FetchX ++ extra_feilds(R)).
+    eval(FetchX ++ extra_fields(R)).
 
-extra_feilds({_, Infos, _Stats} = R) ->
-    extra_feilds(
+extra_fields({_, Infos, _Stats} = R) ->
+    extra_fields(
         maps:get(protocol, maps:get(clientinfo, Infos)),
         R
     ).
 
-extra_feilds(lwm2m, {_, Infos, _Stats}) ->
+extra_fields(lwm2m, {_, Infos, _Stats}) ->
     ClientInfo = maps:get(clientinfo, Infos, #{}),
     [
         {endpoint_name, ClientInfo},
         {lifetime, ClientInfo}
     ];
-extra_feilds(_, _) ->
+extra_fields(_, _) ->
     [].
 
 eval(Ls) ->
@@ -495,7 +495,7 @@ schema("/gateway/:name/clients/:clientid/subscriptions") ->
                         #{
                             200 => emqx_dashboard_swagger:schema_with_examples(
                                 hoconsc:array(ref(subscription)),
-                                examples_subsctiption_list()
+                                examples_subscription_list()
                             )
                         }
                     )
@@ -506,14 +506,14 @@ schema("/gateway/:name/clients/:clientid/subscriptions") ->
                 parameters => params_client_insta(),
                 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
                     ref(subscription),
-                    examples_subsctiption()
+                    examples_subscription()
                 ),
                 responses =>
                     ?STANDARD_RESP(
                         #{
                             201 => emqx_dashboard_swagger:schema_with_examples(
                                 ref(subscription),
-                                examples_subsctiption()
+                                examples_subscription()
                             )
                         }
                     )
@@ -664,7 +664,7 @@ params_paging() ->
     [
         {page,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     required => false,
@@ -674,7 +674,7 @@ params_paging() ->
             )},
         {limit,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     desc => <<"Page Limit">>,
@@ -1089,7 +1089,7 @@ examples_client() ->
             }
     }.
 
-examples_subsctiption_list() ->
+examples_subscription_list() ->
     #{
         general_subscription_list =>
             #{
@@ -1103,7 +1103,7 @@ examples_subsctiption_list() ->
             }
     }.
 
-examples_subsctiption() ->
+examples_subscription() ->
     #{
         general_subscription =>
             #{

+ 8 - 6
apps/emqx_gateway/src/emqx_gateway_api_listeners.erl

@@ -191,7 +191,7 @@ users(get, #{bindings := #{name := Name0, id := Id}, query_string := Qs}) ->
         Name0,
         Id,
         fun(_GwName, #{id := AuthId, chain_name := ChainName}) ->
-            emqx_authn_api:list_users(ChainName, AuthId, page_pramas(Qs))
+            emqx_authn_api:list_users(ChainName, AuthId, page_params(Qs))
         end
     );
 users(post, #{
@@ -261,7 +261,7 @@ import_users(post, #{
 %%--------------------------------------------------------------------
 %% Utils
 
-page_pramas(Qs) ->
+page_params(Qs) ->
     maps:with([<<"page">>, <<"limit">>], Qs).
 
 %%--------------------------------------------------------------------
@@ -555,7 +555,7 @@ params_paging_in_qs() ->
     [
         {page,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     required => false,
@@ -565,7 +565,7 @@ params_paging_in_qs() ->
             )},
         {limit,
             mk(
-                integer(),
+                pos_integer(),
                 #{
                     in => query,
                     required => false,
@@ -627,10 +627,12 @@ fields(tcp_listener_opts) ->
         {high_watermark, mk(binary(), #{})},
         {nodelay, mk(boolean(), #{})},
         {reuseaddr, boolean()},
+        %% TODO: duri
         {send_timeout, binary()},
         {send_timeout_close, boolean()}
     ];
 fields(ssl_listener_opts) ->
+    %% TODO: maybe use better ssl options schema from emqx_ssl_lib or somewhere
     [
         {cacertfile, binary()},
         {certfile, binary()},
@@ -762,7 +764,7 @@ common_listener_opts() ->
                     required => false,
                     desc =>
                         <<
-                            "The Mounpoint for clients of the listener. "
+                            "The Mountpoint for clients of the listener. "
                             "The gateway-level mountpoint configuration can be overloaded "
                             "when it is not null or empty string"
                         >>
@@ -774,7 +776,7 @@ common_listener_opts() ->
                 emqx_authn_schema:authenticator_type(),
                 #{
                     required => {false, recursively},
-                    desc => <<"The authenticatior for this listener">>
+                    desc => <<"The authenticator for this listener">>
                 }
             )}
     ] ++ emqx_gateway_schema:proxy_protocol_opts().

+ 5 - 5
apps/emqx_gateway/src/emqx_gateway_schema.erl

@@ -28,9 +28,9 @@
 -include_lib("typerefl/include/types.hrl").
 
 -type ip_port() :: tuple().
--type duration() :: integer().
--type duration_s() :: integer().
--type bytesize() :: integer().
+-type duration() :: non_neg_integer().
+-type duration_s() :: non_neg_integer().
+-type bytesize() :: pos_integer().
 -type comma_separated_list() :: list().
 
 -typerefl_from_string({ip_port/0, emqx_schema, to_ip_port}).
@@ -117,7 +117,7 @@ fields(stomp_frame) ->
     [
         {max_headers,
             sc(
-                integer(),
+                non_neg_integer(),
                 #{
                     default => 10,
                     desc => "The maximum number of Header"
@@ -125,7 +125,7 @@ fields(stomp_frame) ->
             )},
         {max_headers_length,
             sc(
-                integer(),
+                non_neg_integer(),
                 #{
                     default => 1024,
                     desc => "The maximum string length of the Header Value"

+ 1 - 1
apps/emqx_management/src/emqx_mgmt_api_metrics.erl

@@ -264,4 +264,4 @@ properties() ->
     ].
 
 m(K, Desc) ->
-    {K, mk(integer(), #{desc => Desc})}.
+    {K, mk(non_neg_integer(), #{desc => Desc})}.

+ 25 - 66
apps/emqx_management/src/emqx_mgmt_api_stats.erl

@@ -63,72 +63,29 @@ fields(aggregate) ->
              , example => false})}
     ];
 fields(node_stats_data) ->
-    [ { 'channels.count'
-      , mk( integer(), #{ desc => <<"sessions.count">>
-                        , example => 0})}
-    , { 'channels.max'
-      , mk( integer(), #{ desc => <<"session.max">>
-                        , example => 0})}
-    , { 'connections.count'
-      , mk( integer(), #{ desc => <<"Number of current connections">>
-                        , example => 0})}
-    , { 'connections.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of connections">>
-                        , example => 0})}
-    , { 'delayed.count'
-      , mk( integer(), #{ desc => <<"Number of delayed messages">>
-                        , example => 0})}
-    , { 'delayed.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of delayed messages">>
-                        , example => 0})}
-    , { 'live_connections.count'
-      , mk( integer(), #{ desc => <<"Number of current live connections">>
-                        , example => 0})}
-    , { 'live_connections.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of live connections">>
-                        , example => 0})}
-    , { 'retained.count'
-      , mk( integer(), #{ desc => <<"Number of currently retained messages">>
-                        , example => 0})}
-    , { 'retained.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of retained messages">>
-                        , example => 0})}
-    , { 'sessions.count'
-      , mk( integer(), #{ desc => <<"Number of current sessions">>
-                        , example => 0})}
-    , { 'sessions.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of sessions">>
-                        , example => 0})}
-    , { 'suboptions.count'
-      , mk( integer(), #{ desc => <<"subscriptions.count">>
-                        , example => 0})}
-    , { 'suboptions.max'
-      , mk( integer(), #{ desc => <<"subscriptions.max">>
-                        , example => 0})}
-    , { 'subscribers.count'
-      , mk( integer(), #{ desc => <<"Number of current subscribers">>
-                        , example => 0})}
-    , { 'subscribers.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of subscribers">>
-                        , example => 0})}
-    , { 'subscriptions.count'
-      , mk( integer(), #{ desc => <<"Number of current subscriptions, including shared subscriptions">>
-                        , example => 0})}
-    , { 'subscriptions.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of subscriptions">>
-                        , example => 0})}
-    , { 'subscriptions.shared.count'
-      , mk( integer(), #{ desc => <<"Number of current shared subscriptions">>
-                        , example => 0})}
-    , { 'subscriptions.shared.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of shared subscriptions">>
-                        , example => 0})}
-    , { 'topics.count'
-      , mk( integer(), #{ desc => <<"Number of current topics">>
-                        , example => 0})}
-    , { 'topics.max'
-      , mk( integer(), #{ desc => <<"Historical maximum number of topics">>
-                        , example => 0})}
+    [
+        stats_schema('channels.count', <<"sessions.count">>),
+        stats_schema('channels.max', <<"session.max">>),
+        stats_schema('connections.count', <<"Number of current connections">>),
+        stats_schema('connections.max', <<"Historical maximum number of connections">>),
+        stats_schema('delayed.count', <<"Number of delayed messages">>),
+        stats_schema('delayed.max', <<"Historical maximum number of delayed messages">>),
+        stats_schema('live_connections.count', <<"Number of current live connections">>),
+        stats_schema('live_connections.max', <<"Historical maximum number of live connections">>),
+        stats_schema('retained.count', <<"Number of currently retained messages">>),
+        stats_schema('retained.max', <<"Historical maximum number of retained messages">>),
+        stats_schema('sessions.count', <<"Number of current sessions">>),
+        stats_schema('sessions.max', <<"Historical maximum number of sessions">>),
+        stats_schema('suboptions.count', <<"subscriptions.count">>),
+        stats_schema('suboptions.max', <<"subscriptions.max">>),
+        stats_schema('subscribers.count', <<"Number of current subscribers">>),
+        stats_schema('subscribers.max', <<"Historical maximum number of subscribers">>),
+        stats_schema('subscriptions.count', <<"Number of current subscriptions, including shared subscriptions">>),
+        stats_schema('subscriptions.max', <<"Historical maximum number of subscriptions">>),
+        stats_schema('subscriptions.shared.count', <<"Number of current shared subscriptions">>),
+        stats_schema('subscriptions.shared.max', <<"Historical maximum number of shared subscriptions">>),
+        stats_schema('topics.count', <<"Number of current topics">>),
+        stats_schema('topics.max', <<"Historical maximum number of topics">>)
     ];
 fields(aggergate_data) ->
     [ { node
@@ -136,6 +93,8 @@ fields(aggergate_data) ->
                        , example => <<"emqx@127.0.0.1">>})}
     ] ++ fields(node_stats_data).
 
+stats_schema(Name, Desc) ->
+    {Name, mk(non_neg_integer(), #{desc => Desc, example => 0})}.
 
 %%%==============================================================================================
 %% api apply

+ 6 - 6
apps/emqx_modules/src/emqx_delayed_api.erl

@@ -149,9 +149,9 @@ schema("/mqtt/delayed/messages") ->
                     [
                         {data, mk(hoconsc:array(ref("message")), #{})},
                         {meta, [
-                            {page, mk(integer(), #{})},
-                            {limit, mk(integer(), #{})},
-                            {count, mk(integer(), #{})}
+                            {page, mk(pos_integer(), #{})},
+                            {limit, mk(pos_integer(), #{})},
+                            {count, mk(non_neg_integer(), #{})}
                         ]}
                     ]
             }
@@ -163,11 +163,11 @@ fields("message_without_payload") ->
         {msgid, mk(integer(), #{desc => <<"Message Id (MQTT message id hash)">>})},
         {node, mk(binary(), #{desc => <<"The node where message from">>})},
         {publish_at, mk(binary(), #{desc => <<"Client publish message time, rfc 3339">>})},
-        {delayed_interval, mk(integer(), #{desc => <<"Delayed interval, second">>})},
-        {delayed_remaining, mk(integer(), #{desc => <<"Delayed remaining, second">>})},
+        {delayed_interval, mk(pos_integer(), #{desc => <<"Delayed interval, second">>})},
+        {delayed_remaining, mk(non_neg_integer(), #{desc => <<"Delayed remaining, second">>})},
         {expected_at, mk(binary(), #{desc => <<"Expect publish time, rfc 3339">>})},
         {topic, mk(binary(), #{desc => <<"Topic">>, example => <<"/sys/#">>})},
-        {qos, mk(binary(), #{desc => <<"QoS">>})},
+        {qos, mk(emqx_schema:qos(), #{desc => <<"QoS">>})},
         {from_clientid, mk(binary(), #{desc => <<"From ClientId">>})},
         {from_username, mk(binary(), #{desc => <<"From Username">>})}
     ];

+ 6 - 4
apps/emqx_plugin_libs/src/emqx_plugin_libs_metrics.erl

@@ -307,17 +307,19 @@ calculate_rate(CurrVal, #rate{max = MaxRate0, last_v = LastVal,
 
     %% calculate the max rate since the emqx startup
     MaxRate =
-        if MaxRate0 >= CurrRate -> MaxRate0;
-           true -> CurrRate
+        case MaxRate0 >= CurrRate of
+            true -> MaxRate0;
+            false -> CurrRate
         end,
 
     %% calculate the average rate in last 5 mins
     {Last5MinSamples, Acc5Min, Last5Min} =
-        if Tick =< ?SAMPCOUNT_5M ->
+        case Tick =< ?SAMPCOUNT_5M of
+            true ->
                 Acc = AccRate5Min0 + CurrRate,
                 {lists:reverse([CurrRate | lists:reverse(Last5MinSamples0)]),
                  Acc, Acc / Tick};
-           true ->
+            false ->
                 [FirstRate | Rates] = Last5MinSamples0,
                 Acc =  AccRate5Min0 + CurrRate - FirstRate,
                 {lists:reverse([CurrRate | lists:reverse(Rates)]),

+ 11 - 11
apps/emqx_rule_engine/src/emqx_rule_api_schema.erl

@@ -53,7 +53,7 @@ fields("rule_info") ->
          })}
     ] ++ fields("rule_creation");
 
-%% TODO: we can delete this API if the Dashboard not denpends on it
+%% TODO: we can delete this API if the Dashboard not depends on it
 fields("rule_events") ->
     ETopics = [binary_to_atom(emqx_rule_events:event_topic(E)) || E <- emqx_rule_events:event_names()],
     [ {"event", sc(hoconsc:enum(ETopics), #{desc => "The event topics", required => true})}
@@ -83,39 +83,39 @@ fields("rule_test") ->
     ];
 
 fields("metrics") ->
-    [ {"sql.matched", sc(integer(), #{
+    [ {"sql.matched", sc(non_neg_integer(), #{
             desc => "How much times the FROM clause of the SQL is matched."
         })}
     , {"sql.matched.rate", sc(float(), #{desc => "The rate of matched, times/second"})}
     , {"sql.matched.rate.max", sc(float(), #{desc => "The max rate of matched, times/second"})}
     , {"sql.matched.rate.last5m", sc(float(),
         #{desc => "The average rate of matched in last 5 minutes, times/second"})}
-    , {"sql.passed", sc(integer(), #{desc => "How much times the SQL is passed"})}
-    , {"sql.failed", sc(integer(), #{desc => "How much times the SQL is failed"})}
-    , {"sql.failed.exception", sc(integer(), #{
+    , {"sql.passed", sc(non_neg_integer(), #{desc => "How much times the SQL is passed"})}
+    , {"sql.failed", sc(non_neg_integer(), #{desc => "How much times the SQL is failed"})}
+    , {"sql.failed.exception", sc(non_neg_integer(), #{
             desc => "How much times the SQL is failed due to exceptions. "
                     "This may because of a crash when calling a SQL function, or "
                     "trying to do arithmetic operation on undefined variables"
         })}
-    , {"sql.failed.unknown", sc(integer(), #{
+    , {"sql.failed.unknown", sc(non_neg_integer(), #{
             desc => "How much times the SQL is failed due to an unknown error."
         })}
-    , {"outputs.total", sc(integer(), #{
+    , {"outputs.total", sc(non_neg_integer(), #{
             desc => "How much times the outputs are called by the rule. "
                     "This value may several times of 'sql.matched', depending on the "
                     "number of the outputs of the rule."
         })}
-    , {"outputs.success", sc(integer(), #{
+    , {"outputs.success", sc(non_neg_integer(), #{
             desc => "How much times the rule success to call the outputs."
         })}
-    , {"outputs.failed", sc(integer(), #{
+    , {"outputs.failed", sc(non_neg_integer(), #{
             desc => "How much times the rule failed to call the outputs."
         })}
-    , {"outputs.failed.out_of_service", sc(integer(), #{
+    , {"outputs.failed.out_of_service", sc(non_neg_integer(), #{
             desc => "How much times the rule failed to call outputs due to the output is "
                     "out of service. For example, a bridge is disabled or stopped."
         })}
-    , {"outputs.failed.unknown", sc(integer(), #{
+    , {"outputs.failed.unknown", sc(non_neg_integer(), #{
             desc => "How much times the rule failed to call outputs due to to an unknown error."
         })}
     ];

+ 8 - 8
apps/emqx_rule_engine/src/emqx_rule_engine_api.erl

@@ -99,7 +99,7 @@ rule_info_schema() ->
 
 schema("/rules") ->
     #{
-        operationId => '/rules',
+        'operationId' => '/rules',
         get => #{
             tags => [<<"rules">>],
             description => <<"List all rules">>,
@@ -111,7 +111,7 @@ schema("/rules") ->
             tags => [<<"rules">>],
             description => <<"Create a new rule using given Id">>,
             summary => <<"Create a Rule">>,
-            requestBody => rule_creation_schema(),
+            'requestBody' => rule_creation_schema(),
             responses => #{
                 400 => error_schema('BAD_REQUEST', "Invalid Parameters"),
                 201 => rule_info_schema()
@@ -120,7 +120,7 @@ schema("/rules") ->
 
 schema("/rule_events") ->
     #{
-        operationId => '/rule_events',
+        'operationId' => '/rule_events',
         get => #{
             tags => [<<"rules">>],
             description => <<"List all events can be used in rules">>,
@@ -133,7 +133,7 @@ schema("/rule_events") ->
 
 schema("/rules/:id") ->
     #{
-        operationId => '/rules/:id',
+        'operationId' => '/rules/:id',
         get => #{
             tags => [<<"rules">>],
             description => <<"Get a rule by given Id">>,
@@ -149,7 +149,7 @@ schema("/rules/:id") ->
             description => <<"Update a rule by given Id to all nodes in the cluster">>,
             summary => <<"Update a Rule">>,
             parameters => param_path_id(),
-            requestBody => rule_creation_schema(),
+            'requestBody' => rule_creation_schema(),
             responses => #{
                 400 => error_schema('BAD_REQUEST', "Invalid Parameters"),
                 200 => rule_info_schema()
@@ -168,7 +168,7 @@ schema("/rules/:id") ->
 
 schema("/rules/:id/reset_metrics") ->
     #{
-        operationId => '/rules/:id/reset_metrics',
+        'operationId' => '/rules/:id/reset_metrics',
         put => #{
             tags => [<<"rules">>],
             description => <<"Reset a rule metrics">>,
@@ -183,12 +183,12 @@ schema("/rules/:id/reset_metrics") ->
 
 schema("/rule_test") ->
     #{
-        operationId => '/rule_test',
+        'operationId' => '/rule_test',
         post => #{
             tags => [<<"rules">>],
             description => <<"Test a rule">>,
             summary => <<"Test a Rule">>,
-            requestBody => rule_test_schema(),
+            'requestBody' => rule_test_schema(),
             responses => #{
                 400 => error_schema('BAD_REQUEST', "Invalid Parameters"),
                 412 => error_schema('NOT_MATCH', "SQL Not Match"),

+ 7 - 7
apps/emqx_rule_engine/src/emqx_rule_runtime.erl

@@ -48,9 +48,9 @@
 -spec(apply_rules(list(rule()), input()) -> ok).
 apply_rules([], _Input) ->
     ok;
-apply_rules([#{enable := false}|More], Input) ->
+apply_rules([#{enable := false} | More], Input) ->
     apply_rules(More, Input);
-apply_rules([Rule|More], Input) ->
+apply_rules([Rule | More], Input) ->
     apply_rule_discard_result(Rule, Input),
     apply_rules(More, Input).
 
@@ -150,14 +150,14 @@ select_and_transform(Fields, Input) ->
 
 select_and_transform([], _Input, Output) ->
     Output;
-select_and_transform(['*'|More], Input, Output) ->
+select_and_transform(['*' | More], Input, Output) ->
     select_and_transform(More, Input, maps:merge(Output, Input));
-select_and_transform([{as, Field, Alias}|More], Input, Output) ->
+select_and_transform([{as, Field, Alias} | More], Input, Output) ->
     Val = eval(Field, Input),
     select_and_transform(More,
         nested_put(Alias, Val, Input),
         nested_put(Alias, Val, Output));
-select_and_transform([Field|More], Input, Output) ->
+select_and_transform([Field | More], Input, Output) ->
     Val = eval(Field, Input),
     Key = alias(Field),
     select_and_transform(More,
@@ -172,7 +172,7 @@ select_and_collect(Fields, Input) ->
 select_and_collect([{as, Field, {_, A} = Alias}], Input, {Output, _}) ->
     Val = eval(Field, Input),
     {nested_put(Alias, Val, Output), {A, ensure_list(Val)}};
-select_and_collect([{as, Field, Alias}|More], Input, {Output, LastKV}) ->
+select_and_collect([{as, Field, Alias} | More], Input, {Output, LastKV}) ->
     Val = eval(Field, Input),
     select_and_collect(More,
         nested_put(Alias, Val, Input),
@@ -181,7 +181,7 @@ select_and_collect([Field], Input, {Output, _}) ->
     Val = eval(Field, Input),
     Key = alias(Field),
     {nested_put(Key, Val, Output), {'item', ensure_list(Val)}};
-select_and_collect([Field|More], Input, {Output, LastKV}) ->
+select_and_collect([Field | More], Input, {Output, LastKV}) ->
     Val = eval(Field, Input),
     Key = alias(Field),
     select_and_collect(More,

+ 2 - 2
apps/emqx_slow_subs/src/emqx_slow_subs_api.erl

@@ -50,8 +50,8 @@ schema(("/slow_subscriptions")) ->
                  },
       get => #{tags => [<<"slow subs">>],
                description => <<"Get slow topics statistics record data">>,
-               parameters => [ {page, mk(integer(), #{in => query})}
-                             , {limit, mk(integer(), #{in => query})}
+               parameters => [ {page, mk(pos_integer(), #{in => query})}
+                             , {limit, mk(pos_integer(), #{in => query})}
                              ],
                'requestBody' => [],
                responses => #{200 => [{data, mk(hoconsc:array(ref(record)), #{})}]}

+ 1 - 1
apps/emqx_slow_subs/src/emqx_slow_subs_schema.erl

@@ -19,7 +19,7 @@ fields("slow_subs") ->
           "300s",
           "The eviction time of the record, which in the statistics record table.")}
     , {top_k_num,
-       sc(integer(),
+       sc(pos_integer(),
           10,
           "The maximum number of records in the slow subscription statistics record table.")}
     , {stats_type,

+ 1 - 1
apps/emqx_slow_subs/test/emqx_slow_subs_api_SUITE.erl

@@ -96,7 +96,7 @@ t_get_history(_) ->
 
     lists:foreach(Each, lists:seq(1, 5)),
 
-    {ok, Data} = request_api(get, api_path(["slow_subscriptions"]), "_page=1&_limit=10",
+    {ok, Data} = request_api(get, api_path(["slow_subscriptions"]), "page=1&limit=10",
                              auth_header_()),
     #{<<"data">> := [First | _]} = emqx_json:decode(Data, [return_maps]),
 

+ 1 - 1
mix.exs

@@ -48,7 +48,7 @@ defmodule EMQXUmbrella.MixProject do
     [
       {:lc, github: "emqx/lc", tag: "0.2.1"},
       {:redbug, "2.0.7"},
-      {:typerefl, github: "ieQu1/typerefl", tag: "0.8.6", override: true},
+      {:typerefl, github: "ieQu1/typerefl", tag: "0.9.0", override: true},
       {:ehttpc, github: "emqx/ehttpc", tag: "0.1.12"},
       {:gproc, github: "uwiger/gproc", tag: "0.8.0", override: true},
       {:jiffy, github: "emqx/jiffy", tag: "1.0.5", override: true},

+ 1 - 1
rebar.config

@@ -47,7 +47,7 @@
     [ {lc, {git, "https://github.com/emqx/lc.git", {tag, "0.2.1"}}}
     , {redbug, "2.0.7"}
     , {gpb, "4.11.2"} %% gpb only used to build, but not for release, pin it here to avoid fetching a wrong version due to rebar plugins scattered in all the deps
-    , {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.8.6"}}}
+    , {typerefl, {git, "https://github.com/ieQu1/typerefl", {tag, "0.9.0"}}}
     , {ehttpc, {git, "https://github.com/emqx/ehttpc", {tag, "0.1.12"}}}
     , {gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}}
     , {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}