Sfoglia il codice sorgente

Merge pull request #6848 from JimMoen/refactor-api

refactor api swagger spec via hoconsc
JimMoen 4 anni fa
parent
commit
05d6c40717

+ 2 - 0
apps/emqx_management/src/emqx_mgmt_api_nodes.erl

@@ -100,6 +100,7 @@ node_metrics_api() ->
             parameters => parameters(),
             responses => #{
                 <<"400">> => error_schema(<<"Node error">>, ['SOURCE_ERROR']),
+                %% TODO: Node Metrics Schema
                 <<"200">> => schema(metrics, <<"Get EMQ X Node Metrics">>)}}},
     {"/nodes/:node_name/metrics", Metadata, node_metrics}.
 
@@ -110,6 +111,7 @@ node_stats_api() ->
             parameters => parameters(),
             responses => #{
                 <<"400">> => error_schema(<<"Node error">>, ['SOURCE_ERROR']),
+                %% TODO: Node Stats Schema
                 <<"200">> => schema(stat, <<"Get EMQ X Node Stats">>)}}},
     {"/nodes/:node_name/stats", Metadata, node_stats}.
 

+ 119 - 64
apps/emqx_management/src/emqx_mgmt_api_stats.erl

@@ -17,82 +17,137 @@
 
 -behaviour(minirest_api).
 
--export([api_spec/0]).
+-include_lib("typerefl/include/types.hrl").
+
+-import( hoconsc
+       , [ mk/2
+         , ref/1
+         , ref/2
+         , array/1]).
+
+-export([ api_spec/0
+        , paths/0
+        , schema/1
+        , fields/1
+        ]).
 
 -export([list/2]).
 
 api_spec() ->
-    {[stats_api()], stats_schema()}.
+    emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
+
+paths() ->
+    ["/stats"].
 
-stats_schema() ->
-    Stats = #{
-        type => array,
-        items => #{
-            type => object,
-            properties => emqx_mgmt_util:properties([{'node', string} | properties()])
-        }
-    },
-    Stat = #{
-        type => object,
-        properties => emqx_mgmt_util:properties(properties())
-    },
-    StatsInfo =#{
-        oneOf => [ minirest:ref(stats)
-                 , minirest:ref(stat)
-                 ]
-    },
-    [#{stats => Stats, stat => Stat, stats_info => StatsInfo}].
+schema("/stats") ->
+    #{ 'operationId' => list
+     , get =>
+           #{ description => <<"EMQ X stats">>
+            , tags => [<<"stats">>]
+            , parameters => [ref(aggregate)]
+            , responses =>
+                  #{ 200 => mk( hoconsc:union([ ref(?MODULE, base_data)
+                                              , array(ref(?MODULE, aggergate_data))
+                                              ])
+                              , #{ desc => <<"List stats ok">> })
+                   }
+            }
+     }.
 
-properties() ->
-    [
-        {'channels.count',             integer, <<"sessions.count">>},
-        {'channels.max',               integer, <<"session.max">>},
-        {'connections.count',          integer, <<"Number of current connections">>},
-        {'connections.max',            integer, <<"Historical maximum number of connections">>},
-        {'retained.count',             integer, <<"Number of currently retained messages">>},
-        {'retained.max',               integer, <<"Historical maximum number of retained messages">>},
-        {'routes.count',               integer, <<"Number of current routes">>},
-        {'routes.max',                 integer, <<"Historical maximum number of routes">>},
-        {'sessions.count',             integer, <<"Number of current sessions">>},
-        {'sessions.max',               integer, <<"Historical maximum number of sessions">>},
-        {'suboptions.count',           integer, <<"subscriptions.count">>},
-        {'suboptions.max',             integer, <<"subscriptions.max">>},
-        {'subscribers.count',          integer, <<"Number of current subscribers">>},
-        {'subscribers.max',            integer, <<"Historical maximum number of subscribers">>},
-        {'subscriptions.count',        integer, <<"Number of current subscriptions, including shared subscriptions">>},
-        {'subscriptions.max',          integer, <<"Historical maximum number of subscriptions">>},
-        {'subscriptions.shared.count', integer, <<"Number of current shared subscriptions">>},
-        {'subscriptions.shared.max',   integer, <<"Historical maximum number of shared subscriptions">>},
-        {'topics.count',               integer, <<"Number of current topics">>},
-        {'topics.max',                 integer, <<"Historical maximum number of topics">>}
-    ].
+fields(aggregate) ->
+    [ { aggregate
+      , mk( boolean()
+          , #{ desc => <<"Calculation aggregate for all nodes">>
+             , in => query
+             , nullable => true
+             , example => false})}
+    ];
+fields(base_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})}
+    , { 'routes.count'
+      , mk( integer(), #{ desc => <<"Number of current routes">>
+                        , example => 0})}
+    , { 'routes.max'
+      , mk( integer(), #{ desc => <<"Historical maximum number of routes">>
+                        , 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})}
+    ];
+fields(aggergate_data) ->
+    [ { node
+      , mk( string(), #{ desc => <<"Node name">>
+                       , example => <<"emqx@127.0.0.1">>})}
+    ] ++ fields(base_data).
 
-stats_api() ->
-    Metadata = #{
-        get => #{
-            description => <<"EMQ X stats">>,
-            parameters => [#{
-                name => aggregate,
-                in => query,
-                schema => #{type => boolean}
-            }],
-            responses => #{
-                <<"200">> => #{
-                    description => <<"List stats ok">>,
-                    content => #{
-                        'application/json' => #{
-                            schema => minirest:ref(<<"stats_info">>)
-                        }
-                    }
-                }
-            }}},
-    {"/stats", Metadata, list}.
 
 %%%==============================================================================================
 %% api apply
 list(get, #{query_string := Qs}) ->
     case maps:get(<<"aggregate">>, Qs, undefined) of
-        <<"true">> ->
+        true ->
             {200, emqx_mgmt:get_stats()};
         _ ->
             Data = [maps:from_list(emqx_mgmt:get_stats(Node) ++ [{node, Node}]) ||

+ 29 - 13
apps/emqx_management/src/emqx_mgmt_api_status.erl

@@ -17,22 +17,40 @@
 %% API
 -behaviour(minirest_api).
 
--export([api_spec/0]).
+-export([ api_spec/0
+        , paths/0
+        , schema/1
+        ]).
 
 -export([running_status/2]).
 
 api_spec() ->
-    {[status_api()], []}.
+    emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
 
-status_api() ->
-    Path = "/status",
-    Metadata = #{
-        get => #{
-            security => [],
-            responses => #{<<"200">> => #{description => <<"running">>}}
-        }
-    },
-    {Path, Metadata, running_status}.
+paths() ->
+    ["/status"].
+
+schema("/status") ->
+    #{ 'operationId' => running_status
+     , get =>
+           #{ description => <<"Node running status">>
+            , security => []
+            , responses =>
+                  #{200 =>
+                        #{ description => <<"Node is running">>
+                         , content =>
+                              #{ 'text/plain' =>
+                                     #{ schema => #{type => string}
+                                      , example => <<"Node emqx@127.0.0.1 is started\nemqx is running">>}
+                               }
+                         }
+                   }
+            }
+     }.
+
+%%--------------------------------------------------------------------
+%% API Handler funcs
+%%--------------------------------------------------------------------
 
 running_status(get, _Params) ->
     {InternalStatus, _ProvidedStatus} = init:get_status(),
@@ -44,5 +62,3 @@ running_status(get, _Params) ->
     Status = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), InternalStatus, AppStatus]),
     Body = list_to_binary(Status),
     {200, #{<<"content-type">> => <<"text/plain">>}, Body}.
-
-

+ 2 - 4
apps/emqx_prometheus/src/emqx_prometheus_api.erl

@@ -116,10 +116,8 @@ prometheus_data_schema() ->
     #{ description => <<"Get Prometheus Data">>
      , content =>
            #{ 'application/json' =>
-                  #{ schema => #{type => object}
-                   , description => <<"Prometheus Data in json">>}
+                  #{schema => #{type => object}}
             , 'text/plain' =>
-                  #{ schema => #{type => string}
-                   , description => <<"Prometheus Data in text/plain">>}
+                  #{schema => #{type => string}}
             }
      }.