From 92ae5663a672d9dc88b5a29c0df7f423912ef9d4 Mon Sep 17 00:00:00 2001 From: DDDHuang <904897578@qq.com> Date: Fri, 16 Jul 2021 18:43:53 +0800 Subject: [PATCH] feat: update to openapi 3.0.0 --- .../src/emqx_mgmt_api_clients.erl | 347 ++++++------ .../src/emqx_mgmt_api_metrics.erl | 505 +++++++++--------- .../src/emqx_mgmt_api_nodes.erl | 151 +++--- .../src/emqx_mgmt_api_publish.erl | 94 ++-- .../src/emqx_mgmt_api_stats.erl | 137 ++--- apps/emqx_management/src/emqx_mgmt_http.erl | 16 +- apps/emqx_management/src/emqx_mgmt_util.erl | 79 ++- rebar.config | 2 +- 8 files changed, 682 insertions(+), 649 deletions(-) diff --git a/apps/emqx_management/src/emqx_mgmt_api_clients.erl b/apps/emqx_management/src/emqx_mgmt_api_clients.erl index 138b61097..bfdbf68e1 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_clients.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_clients.erl @@ -71,144 +71,152 @@ apis() -> , subscribe_api()]. schemas() -> - ClientDef = #{ - <<"node">> => #{ - type => <<"string">>, - description => <<"Name of the node to which the client is connected">>}, - <<"clientid">> => #{ - type => <<"string">>, - description => <<"Client identifier">>}, - <<"username">> => #{ - type => <<"string">>, - description => <<"User name of client when connecting">>}, - <<"proto_name">> => #{ - type => <<"string">>, - description => <<"Client protocol name">>}, - <<"proto_ver">> => #{ - type => <<"integer">>, - description => <<"Protocol version used by the client">>}, - <<"ip_address">> => #{ - type => <<"string">>, - description => <<"Client's IP address">>}, - <<"is_bridge">> => #{ - type => <<"boolean">>, - description => <<"Indicates whether the client is connectedvia bridge">>}, - <<"connected_at">> => #{ - type => <<"string">>, - description => <<"Client connection time">>}, - <<"disconnected_at">> => #{ - type => <<"string">>, - description => <<"Client offline time, This field is only valid and returned when connected is false">>}, - <<"connected">> => #{ - type => <<"boolean">>, - description => <<"Whether the client is connected">>}, - <<"will_msg">> => #{ - type => <<"string">>, - description => <<"Client will message">>}, - <<"zone">> => #{ - type => <<"string">>, - description => <<"Indicate the configuration group used by the client">>}, - <<"keepalive">> => #{ - type => <<"integer">>, - description => <<"keepalive time, with the unit of second">>}, - <<"clean_start">> => #{ - type => <<"boolean">>, - description => <<"Indicate whether the client is using a brand new session">>}, - <<"expiry_interval">> => #{ - type => <<"integer">>, - description => <<"Session expiration interval, with the unit of second">>}, - <<"created_at">> => #{ - type => <<"string">>, - description => <<"Session creation time">>}, - <<"subscriptions_cnt">> => #{ - type => <<"integer">>, - description => <<"Number of subscriptions established by this client.">>}, - <<"subscriptions_max">> => #{ - type => <<"integer">>, - description => <<"v4 api name [max_subscriptions] Maximum number of subscriptions allowed by this client">>}, - <<"inflight_cnt">> => #{ - type => <<"integer">>, - description => <<"Current length of inflight">>}, - <<"inflight_max">> => #{ - type => <<"integer">>, - description => <<"v4 api name [max_inflight]. Maximum length of inflight">>}, - <<"mqueue_len">> => #{ - type => <<"integer">>, - description => <<"Current length of message queue">>}, - <<"mqueue_max">> => #{ - type => <<"integer">>, - description => <<"v4 api name [max_mqueue]. Maximum length of message queue">>}, - <<"mqueue_dropped">> => #{ - type => <<"integer">>, - description => <<"Number of messages dropped by the message queue due to exceeding the length">>}, - <<"awaiting_rel_cnt">> => #{ - type => <<"integer">>, - description => <<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>}, - <<"awaiting_rel_max">> => #{ - type => <<"integer">>, - description => <<"v4 api name [max_awaiting_rel]. Maximum allowed number of awaiting PUBREC packet">>}, - <<"recv_oct">> => #{ - type => <<"integer">>, - description => <<"Number of bytes received by EMQ X Broker (the same below)">>}, - <<"recv_cnt">> => #{ - type => <<"integer">>, - description => <<"Number of TCP packets received">>}, - <<"recv_pkt">> => #{ - type => <<"integer">>, - description => <<"Number of MQTT packets received">>}, - <<"recv_msg">> => #{ - type => <<"integer">>, - description => <<"Number of PUBLISH packets received">>}, - <<"send_oct">> => #{ - type => <<"integer">>, - description => <<"Number of bytes sent">>}, - <<"send_cnt">> => #{ - type => <<"integer">>, - description => <<"Number of TCP packets sent">>}, - <<"send_pkt">> => #{ - type => <<"integer">>, - description => <<"Number of MQTT packets sent">>}, - <<"send_msg">> => #{ - type => <<"integer">>, - description => <<"Number of PUBLISH packets sent">>}, - <<"mailbox_len">> => #{ - type => <<"integer">>, - description => <<"Process mailbox size">>}, - <<"heap_size">> => #{ - type => <<"integer">>, - description => <<"Process heap size with the unit of byte">> - }, - <<"reductions">> => #{ - type => <<"integer">>, - description => <<"Erlang reduction">>}}, - ACLCacheDefinitionProperties = #{ - <<"topic">> => #{ - type => <<"string">>, - description => <<"Topic name">>}, - <<"access">> => #{ - type => <<"string">>, - enum => [<<"subscribe">>, <<"publish">>], - description => <<"Access type">>}, - <<"result">> => #{ - type => <<"string">>, - enum => [<<"allow">>, <<"deny">>], - default => <<"allow">>, - description => <<"Allow or deny">>}, - <<"updated_time">> => #{ - type => <<"integer">>, - description => <<"Update time">>}}, - [{<<"client">>, ClientDef}, {<<"acl_cache">>, ACLCacheDefinitionProperties}]. + Client = #{ + client => #{ + type => object, + properties => #{ + node => #{ + type => string, + description => <<"Name of the node to which the client is connected">>}, + clientid => #{ + type => string, + description => <<"Client identifier">>}, + username => #{ + type => string, + description => <<"User name of client when connecting">>}, + proto_name => #{ + type => string, + description => <<"Client protocol name">>}, + proto_ver => #{ + type => integer, + description => <<"Protocol version used by the client">>}, + ip_address => #{ + type => string, + description => <<"Client's IP address">>}, + is_bridge => #{ + type => boolean, + description => <<"Indicates whether the client is connectedvia bridge">>}, + connected_at => #{ + type => string, + description => <<"Client connection time">>}, + disconnected_at => #{ + type => string, + description => <<"Client offline time, This field is only valid and returned when connected is false">>}, + connected => #{ + type => boolean, + description => <<"Whether the client is connected">>}, + will_msg => #{ + type => string, + description => <<"Client will message">>}, + zone => #{ + type => string, + description => <<"Indicate the configuration group used by the client">>}, + keepalive => #{ + type => integer, + description => <<"keepalive time, with the unit of second">>}, + clean_start => #{ + type => boolean, + description => <<"Indicate whether the client is using a brand new session">>}, + expiry_interval => #{ + type => integer, + description => <<"Session expiration interval, with the unit of second">>}, + created_at => #{ + type => string, + description => <<"Session creation time">>}, + subscriptions_cnt => #{ + type => integer, + description => <<"Number of subscriptions established by this client.">>}, + subscriptions_max => #{ + type => integer, + description => <<"v4 api name [max_subscriptions] Maximum number of subscriptions allowed by this client">>}, + inflight_cnt => #{ + type => integer, + description => <<"Current length of inflight">>}, + inflight_max => #{ + type => integer, + description => <<"v4 api name [max_inflight]. Maximum length of inflight">>}, + mqueue_len => #{ + type => integer, + description => <<"Current length of message queue">>}, + mqueue_max => #{ + type => integer, + description => <<"v4 api name [max_mqueue]. Maximum length of message queue">>}, + mqueue_dropped => #{ + type => integer, + description => <<"Number of messages dropped by the message queue due to exceeding the length">>}, + awaiting_rel_cnt => #{ + type => integer, + description => <<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>}, + awaiting_rel_max => #{ + type => integer, + description => <<"v4 api name [max_awaiting_rel]. Maximum allowed number of awaiting PUBREC packet">>}, + recv_oct => #{ + type => integer, + description => <<"Number of bytes received by EMQ X Broker (the same below)">>}, + recv_cnt => #{ + type => integer, + description => <<"Number of TCP packets received">>}, + recv_pkt => #{ + type => integer, + description => <<"Number of MQTT packets received">>}, + recv_msg => #{ + type => integer, + description => <<"Number of PUBLISH packets received">>}, + send_oct => #{ + type => integer, + description => <<"Number of bytes sent">>}, + send_cnt => #{ + type => integer, + description => <<"Number of TCP packets sent">>}, + send_pkt => #{ + type => integer, + description => <<"Number of MQTT packets sent">>}, + send_msg => #{ + type => integer, + description => <<"Number of PUBLISH packets sent">>}, + mailbox_len => #{ + type => integer, + description => <<"Process mailbox size">>}, + heap_size => #{ + type => integer, + description => <<"Process heap size with the unit of byte">> + }, + reductions => #{ + type => integer, + description => <<"Erlang reduction">>} + } + } + }, + AclCache = #{ + acl_cache => #{ + type => object, + properties => #{ + topic => #{ + type => string, + description => <<"Topic name">>}, + access => #{ + type => string, + enum => [<<"subscribe">>, <<"publish">>], + description => <<"Access type">>}, + result => #{ + type => string, + enum => [<<"allow">>, <<"deny">>], + default => <<"allow">>, + description => <<"Allow or deny">>}, + updated_time => #{ + type => integer, + description => <<"Update time">>} + } + } + }, + [Client, AclCache]. clients_api() -> Metadata = #{ get => #{ description => "List clients", responses => #{ - <<"200">> => #{ - description => <<"List clients 200 OK">>, - schema => #{ - type => array, - items => minirest:ref(<<"client">>)}}}}}, + <<"200">> => emqx_mgmt_util:response_array_schema(<<"List clients 200 OK">>, <<"client">>)}}}, {"/clients", Metadata, clients}. client_api() -> @@ -218,25 +226,23 @@ client_api() -> parameters => [#{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456}], + example => 123456}], responses => #{ <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), - <<"200">> => #{ - description => <<"Get clients 200 OK">>, - schema => minirest:ref(<<"client">>)}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"List clients 200 OK">>, <<"client">>)}}, delete => #{ description => "Kick out client by client ID", parameters => [#{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456}], + example => 123456}], responses => #{ <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), - <<"200">> => #{description => <<"Kick out clients OK">>}}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"List clients 200 OK">>, <<"client">>)}}}, {"/clients/:clientid", Metadata, client}. clients_acl_cache_api() -> @@ -246,26 +252,23 @@ clients_acl_cache_api() -> parameters => [#{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456}], + example => 123456}], responses => #{ <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), - <<"200">> => #{ - description => <<"List 200 OK">>, - schema => minirest:ref(<<"acl_cache">>)}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"List clients 200 OK">>, <<"acl_cache">>)}}, delete => #{ description => "Clean client acl cache", parameters => [#{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456}], + example => 123456}], responses => #{ - <<"404">> => emqx_mgmt_util:not_found_schema(<<"client id not found">>), - <<"200">> => #{ - description => <<"Clean acl cache 200 OK">>}}}}, + <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), + <<"200">> => emqx_mgmt_util:response_schema(<<"Delete clients 200 OK">>)}}}, {"/clients/:clientid/acl_cache", Metadata, acl_cache}. subscribe_api() -> @@ -276,51 +279,47 @@ subscribe_api() -> #{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456 - }, - #{ - name => topic_data, - in => body, - schema => #{ - type => object, - properties => #{ - <<"topic">> => #{ - type => <<"string">>, - example => <<"topic_1">>, - description => <<"Topic">>}, - <<"qos">> => #{ - type => <<"integer">>, - enum => [0, 1, 2], - example => 0, - description => <<"QOS">>}}} + example => 123456 } ], + 'requestBody' => emqx_mgmt_util:request_body_schema(#{ + type => object, + properties => #{ + <<"topic">> => #{ + type => string, + example => <<"topic_1">>, + description => <<"Topic">>}, + <<"qos">> => #{ + type => integer, + enum => [0, 1, 2], + example => 0, + description => <<"QoS">>}}}), responses => #{ <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), - <<"200">> => #{description => <<"subscribe ok">>}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"subscribe ok">>)}}, delete => #{ description => "unsubscribe", parameters => [ #{ name => clientid, in => path, - type => string, + schema => #{type => string}, required => true, - default => 123456 + example => 123456 }, #{ name => topic, in => query, - type => string, + schema => #{type => string}, required => true, - default => <<"topic_1">> + example => <<"topic_1">> } ], responses => #{ <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), - <<"200">> => #{description => <<"unsubscribe ok">>}}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"unsubscribe ok">>)}}}, {"/clients/:clientid/subscribe", Metadata, subscribe}. %%%============================================================================================== diff --git a/apps/emqx_management/src/emqx_mgmt_api_metrics.erl b/apps/emqx_management/src/emqx_mgmt_api_metrics.erl index d959b0b17..ed9de428d 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_metrics.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_metrics.erl @@ -26,263 +26,266 @@ api_spec() -> {[metrics_api()], [metrics_schema()]}. metrics_schema() -> - DefinitionName = <<"metrics">>, - DefinitionProperties = #{ - <<"actions.failure">> => #{ - type => <<"integer">>, - description => <<"Number of failure executions of the rule engine action">>}, - <<"actions.success">> => #{ - type => <<"integer">>, - description => <<"Number of successful executions of the rule engine action">>}, - <<"bytes.received">> => #{ - type => <<"integer">>, - description => <<"Number of bytes received by EMQ X Broker">>}, - <<"bytes.sent">> => #{ - type => <<"integer">>, - description => <<"Number of bytes sent by EMQ X Broker on this connection">>}, - <<"client.authenticate">> => #{ - type => <<"integer">>, - description => <<"Number of client authentications">>}, - <<"client.auth.anonymous">> => #{ - type => <<"integer">>, - description => <<"Number of clients who log in anonymously">>}, - <<"client.connect">> => #{ - type => <<"integer">>, - description => <<"Number of client connections">>}, - <<"client.connack">> => #{ - type => <<"integer">>, - description => <<"Number of CONNACK packet sent">>}, - <<"client.connected">> => #{ - type => <<"integer">>, - description => <<"Number of successful client connections">>}, - <<"client.disconnected">> => #{ - type => <<"integer">>, - description => <<"Number of client disconnects">>}, - <<"client.check_acl">> => #{ - type => <<"integer">>, - description => <<"Number of ACL rule checks">>}, - <<"client.subscribe">> => #{ - type => <<"integer">>, - description => <<"Number of client subscriptions">>}, - <<"client.unsubscribe">> => #{ - type => <<"integer">>, - description => <<"Number of client unsubscriptions">>}, - <<"delivery.dropped.too_large">> => #{ - type => <<"integer">>, - description => <<"The number of messages that were dropped because the length exceeded the limit when sending">>}, - <<"delivery.dropped.queue_full">> => #{ - type => <<"integer">>, - description => <<"Number of messages with a non-zero QoS that were dropped because the message queue was full when sending">>}, - <<"delivery.dropped.qos0_msg">> => #{ - type => <<"integer">>, - description => <<"Number of messages with QoS 0 that were dropped because the message queue was full when sending">>}, - <<"delivery.dropped.expired">> => #{ - type => <<"integer">>, - description => <<"Number of messages dropped due to message expiration on sending">>}, - <<"delivery.dropped.no_local">> => #{ - type => <<"integer">>, - description => <<"Number of messages that were dropped due to the No Local subscription option when sending">>}, - <<"delivery.dropped">> => #{ - type => <<"integer">>, - description => <<"Total number of discarded messages when sending">>}, - <<"messages.delayed">> => #{ - type => <<"integer">>, - description => <<"Number of delay- published messages stored by EMQ X Broker">>}, - <<"messages.delivered">> => #{ - type => <<"integer">>, - description => <<"Number of messages forwarded to the subscription process internally by EMQ X Broker">>}, - <<"messages.dropped">> => #{ - type => <<"integer">>, - description => <<"Total number of messages dropped by EMQ X Broker before forwarding to the subscription process">>}, - <<"messages.dropped.expired">> => #{ - type => <<"integer">>, - description => <<"Number of messages dropped due to message expiration when receiving">>}, - <<"messages.dropped.no_subscribers">> => #{ - type => <<"integer">>, - description => <<"Number of messages dropped due to no subscribers">>}, - <<"messages.forward">> => #{ - type => <<"integer">>, - description => <<"Number of messages forwarded to other nodes">>}, - <<"messages.publish">> => #{ - type => <<"integer">>, - description => <<"Number of messages published in addition to system messages">>}, - <<"messages.qos0.received">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 0 messages received from clients">>}, - <<"messages.qos1.received">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 1 messages received from clients">>}, - <<"messages.qos2.received">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 2 messages received from clients">>}, - <<"messages.qos0.sent">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 0 messages sent to clients">>}, - <<"messages.qos1.sent">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 1 messages sent to clients">>}, - <<"messages.qos2.sent">> => #{ - type => <<"integer">>, - description => <<"Number of QoS 2 messages sent to clients">>}, - <<"messages.received">> => #{ - type => <<"integer">>, - description => <<"Number of messages received from the client, equal to the sum of messages.qos0.received,messages.qos1.received and messages.qos2.received">>}, - <<"messages.sent">> => #{ - type => <<"integer">>, - description => <<"Number of messages sent to the client, equal to the sum of messages.qos0.sent,messages.qos1.sent and messages.qos2.sent">>}, - <<"messages.retained">> => #{ - type => <<"integer">>, - description => <<"Number of retained messages stored by EMQ X Broker">>}, - <<"messages.acked">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBACK and PUBREC packet">>}, - <<"packets.received">> => #{ - type => <<"integer">>, - description => <<"Number of received packet">>}, - <<"packets.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent packet">>}, - <<"packets.connect.received">> => #{ - type => <<"integer">>, - description => <<"Number of received CONNECT packet">>}, - <<"packets.connack.auth_error">> => #{ - type => <<"integer">>, - description => <<"Number of received CONNECT packet with failed authentication">>}, - <<"packets.connack.error">> => #{ - type => <<"integer">>, - description => <<"Number of received CONNECT packet with unsuccessful connections">>}, - <<"packets.connack.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent CONNACK packet">>}, - <<"packets.publish.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBLISH packet">>}, - <<"packets.publish.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBLISH packet">>}, - <<"packets.publish.inuse">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBLISH packet with occupied identifiers">>}, - <<"packets.publish.auth_error">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBLISH packets with failed the ACL check">>}, - <<"packets.publish.error">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBLISH packet that cannot be published">>}, - <<"packets.publish.dropped">> => #{ - type => <<"integer">>, - description => <<"Number of messages discarded due to the receiving limit">>}, - <<"packets.puback.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBACK packet">>}, - <<"packets.puback.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBACK packet">>}, - <<"packets.puback.inuse">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBACK packet with occupied identifiers">>}, - <<"packets.puback.missed">> => #{ - type => <<"integer">>, - description => <<"Number of received packet with identifiers.">>}, - <<"packets.pubrec.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBREC packet">>}, - <<"packets.pubrec.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBREC packet">>}, - <<"packets.pubrec.inuse">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBREC packet with occupied identifiers">>}, - <<"packets.pubrec.missed">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBREC packet with unknown identifiers">>}, - <<"packets.pubrel.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBREL packet">>}, - <<"packets.pubrel.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBREL packet">>}, - <<"packets.pubrel.missed">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBREC packet with unknown identifiers">>}, - <<"packets.pubcomp.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBCOMP packet">>}, - <<"packets.pubcomp.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBCOMP packet">>}, - <<"packets.pubcomp.inuse">> => #{ - type => <<"integer">>, - description => <<"Number of received PUBCOMP packet with occupied identifiers">>}, - <<"packets.pubcomp.missed">> => #{ - type => <<"integer">>, - description => <<"Number of missed PUBCOMP packet">>}, - <<"packets.subscribe.received">> => #{ - type => <<"integer">>, - description => <<"Number of received SUBSCRIBE packet">>}, - <<"packets.subscribe.error">> => #{ - type => <<"integer">>, - description => <<"Number of received SUBSCRIBE packet with failed subscriptions">>}, - <<"packets.subscribe.auth_error">> => #{ - type => <<"integer">>, - description => <<"Number of received SUBACK packet with failed ACL check">>}, - <<"packets.suback.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent SUBACK packet">>}, - <<"packets.unsubscribe.received">> => #{ - type => <<"integer">>, - description => <<"Number of received UNSUBSCRIBE packet">>}, - <<"packets.unsubscribe.error">> => #{ - type => <<"integer">>, - description => <<"Number of received UNSUBSCRIBE packet with failed unsubscriptions">>}, - <<"packets.unsuback.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent UNSUBACK packet">>}, - <<"packets.pingreq.received">> => #{ - type => <<"integer">>, - description => <<"Number of received PINGREQ packet">>}, - <<"packets.pingresp.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent PUBRESP packet">>}, - <<"packets.disconnect.received">> => #{ - type => <<"integer">>, - description => <<"Number of received DISCONNECT packet">>}, - <<"packets.disconnect.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent DISCONNECT packet">>}, - <<"packets.auth.received">> => #{ - type => <<"integer">>, - description => <<"Number of received AUTH packet">>}, - <<"packets.auth.sent">> => #{ - type => <<"integer">>, - description => <<"Number of sent AUTH packet">>}, - <<"rules.matched">> => #{ - type => <<"integer">>, - description => <<"Number of rule matched">>}, - <<"session.created">> => #{ - type => <<"integer">>, - description => <<"Number of sessions created">>}, - <<"session.discarded">> => #{ - type => <<"integer">>, - description => <<"Number of sessions dropped because Clean Session or Clean Start is true">>}, - <<"session.resumed">> => #{ - type => <<"integer">>, - description => <<"Number of sessions resumed because Clean Session or Clean Start is false">>}, - <<"session.takeovered">> => #{ - type => <<"integer">>, - description => <<"Number of sessions takeovered because Clean Session or Clean Start is false">>}, - <<"session.terminated">> => #{ - type => <<"integer">>, - description => <<"Number of terminated sessions">>}}, - {DefinitionName, DefinitionProperties}. + #{ + metrics => #{ + type => object, + properties => #{ + 'actions.failure' => #{ + type => integer, + description => <<"Number of failure executions of the rule engine action">>}, + 'actions.success' => #{ + type => integer, + description => <<"Number of successful executions of the rule engine action">>}, + 'bytes.received' => #{ + type => integer, + description => <<"Number of bytes received by EMQ X Broker">>}, + 'bytes.sent' => #{ + type => integer, + description => <<"Number of bytes sent by EMQ X Broker on this connection">>}, + 'client.authenticate' => #{ + type => integer, + description => <<"Number of client authentications">>}, + 'client.auth.anonymous' => #{ + type => integer, + description => <<"Number of clients who log in anonymously">>}, + 'client.connect' => #{ + type => integer, + description => <<"Number of client connections">>}, + 'client.connack' => #{ + type => integer, + description => <<"Number of CONNACK packet sent">>}, + 'client.connected' => #{ + type => integer, + description => <<"Number of successful client connections">>}, + 'client.disconnected' => #{ + type => integer, + description => <<"Number of client disconnects">>}, + 'client.check_acl' => #{ + type => integer, + description => <<"Number of ACL rule checks">>}, + 'client.subscribe' => #{ + type => integer, + description => <<"Number of client subscriptions">>}, + 'client.unsubscribe' => #{ + type => integer, + description => <<"Number of client unsubscriptions">>}, + 'delivery.dropped.too_large' => #{ + type => integer, + description => <<"The number of messages that were dropped because the length exceeded the limit when sending">>}, + 'delivery.dropped.queue_full' => #{ + type => integer, + description => <<"Number of messages with a non-zero QoS that were dropped because the message queue was full when sending">>}, + 'delivery.dropped.qos0_msg' => #{ + type => integer, + description => <<"Number of messages with QoS 0 that were dropped because the message queue was full when sending">>}, + 'delivery.dropped.expired' => #{ + type => integer, + description => <<"Number of messages dropped due to message expiration on sending">>}, + 'delivery.dropped.no_local' => #{ + type => integer, + description => <<"Number of messages that were dropped due to the No Local subscription option when sending">>}, + 'delivery.dropped' => #{ + type => integer, + description => <<"Total number of discarded messages when sending">>}, + 'messages.delayed' => #{ + type => integer, + description => <<"Number of delay- published messages stored by EMQ X Broker">>}, + 'messages.delivered' => #{ + type => integer, + description => <<"Number of messages forwarded to the subscription process internally by EMQ X Broker">>}, + 'messages.dropped' => #{ + type => integer, + description => <<"Total number of messages dropped by EMQ X Broker before forwarding to the subscription process">>}, + 'messages.dropped.expired' => #{ + type => integer, + description => <<"Number of messages dropped due to message expiration when receiving">>}, + 'messages.dropped.no_subscribers' => #{ + type => integer, + description => <<"Number of messages dropped due to no subscribers">>}, + 'messages.forward' => #{ + type => integer, + description => <<"Number of messages forwarded to other nodes">>}, + 'messages.publish' => #{ + type => integer, + description => <<"Number of messages published in addition to system messages">>}, + 'messages.qos0.received' => #{ + type => integer, + description => <<"Number of QoS 0 messages received from clients">>}, + 'messages.qos1.received' => #{ + type => integer, + description => <<"Number of QoS 1 messages received from clients">>}, + 'messages.qos2.received' => #{ + type => integer, + description => <<"Number of QoS 2 messages received from clients">>}, + 'messages.qos0.sent' => #{ + type => integer, + description => <<"Number of QoS 0 messages sent to clients">>}, + 'messages.qos1.sent' => #{ + type => integer, + description => <<"Number of QoS 1 messages sent to clients">>}, + 'messages.qos2.sent' => #{ + type => integer, + description => <<"Number of QoS 2 messages sent to clients">>}, + 'messages.received' => #{ + type => integer, + description => <<"Number of messages received from the client, equal to the sum of messages.qos0.received,messages.qos1.received and messages.qos2.received">>}, + 'messages.sent' => #{ + type => integer, + description => <<"Number of messages sent to the client, equal to the sum of messages.qos0.sent,messages.qos1.sent and messages.qos2.sent">>}, + 'messages.retained' => #{ + type => integer, + description => <<"Number of retained messages stored by EMQ X Broker">>}, + 'messages.acked' => #{ + type => integer, + description => <<"Number of received PUBACK and PUBREC packet">>}, + 'packets.received' => #{ + type => integer, + description => <<"Number of received packet">>}, + 'packets.sent' => #{ + type => integer, + description => <<"Number of sent packet">>}, + 'packets.connect.received' => #{ + type => integer, + description => <<"Number of received CONNECT packet">>}, + 'packets.connack.auth_error' => #{ + type => integer, + description => <<"Number of received CONNECT packet with failed authentication">>}, + 'packets.connack.error' => #{ + type => integer, + description => <<"Number of received CONNECT packet with unsuccessful connections">>}, + 'packets.connack.sent' => #{ + type => integer, + description => <<"Number of sent CONNACK packet">>}, + 'packets.publish.received' => #{ + type => integer, + description => <<"Number of received PUBLISH packet">>}, + 'packets.publish.sent' => #{ + type => integer, + description => <<"Number of sent PUBLISH packet">>}, + 'packets.publish.inuse' => #{ + type => integer, + description => <<"Number of received PUBLISH packet with occupied identifiers">>}, + 'packets.publish.auth_error' => #{ + type => integer, + description => <<"Number of received PUBLISH packets with failed the ACL check">>}, + 'packets.publish.error' => #{ + type => integer, + description => <<"Number of received PUBLISH packet that cannot be published">>}, + 'packets.publish.dropped' => #{ + type => integer, + description => <<"Number of messages discarded due to the receiving limit">>}, + 'packets.puback.received' => #{ + type => integer, + description => <<"Number of received PUBACK packet">>}, + 'packets.puback.sent' => #{ + type => integer, + description => <<"Number of sent PUBACK packet">>}, + 'packets.puback.inuse' => #{ + type => integer, + description => <<"Number of received PUBACK packet with occupied identifiers">>}, + 'packets.puback.missed' => #{ + type => integer, + description => <<"Number of received packet with identifiers.">>}, + 'packets.pubrec.received' => #{ + type => integer, + description => <<"Number of received PUBREC packet">>}, + 'packets.pubrec.sent' => #{ + type => integer, + description => <<"Number of sent PUBREC packet">>}, + 'packets.pubrec.inuse' => #{ + type => integer, + description => <<"Number of received PUBREC packet with occupied identifiers">>}, + 'packets.pubrec.missed' => #{ + type => integer, + description => <<"Number of received PUBREC packet with unknown identifiers">>}, + 'packets.pubrel.received' => #{ + type => integer, + description => <<"Number of received PUBREL packet">>}, + 'packets.pubrel.sent' => #{ + type => integer, + description => <<"Number of sent PUBREL packet">>}, + 'packets.pubrel.missed' => #{ + type => integer, + description => <<"Number of received PUBREC packet with unknown identifiers">>}, + 'packets.pubcomp.received' => #{ + type => integer, + description => <<"Number of received PUBCOMP packet">>}, + 'packets.pubcomp.sent' => #{ + type => integer, + description => <<"Number of sent PUBCOMP packet">>}, + 'packets.pubcomp.inuse' => #{ + type => integer, + description => <<"Number of received PUBCOMP packet with occupied identifiers">>}, + 'packets.pubcomp.missed' => #{ + type => integer, + description => <<"Number of missed PUBCOMP packet">>}, + 'packets.subscribe.received' => #{ + type => integer, + description => <<"Number of received SUBSCRIBE packet">>}, + 'packets.subscribe.error' => #{ + type => integer, + description => <<"Number of received SUBSCRIBE packet with failed subscriptions">>}, + 'packets.subscribe.auth_error' => #{ + type => integer, + description => <<"Number of received SUBACK packet with failed ACL check">>}, + 'packets.suback.sent' => #{ + type => integer, + description => <<"Number of sent SUBACK packet">>}, + 'packets.unsubscribe.received' => #{ + type => integer, + description => <<"Number of received UNSUBSCRIBE packet">>}, + 'packets.unsubscribe.error' => #{ + type => integer, + description => <<"Number of received UNSUBSCRIBE packet with failed unsubscriptions">>}, + 'packets.unsuback.sent' => #{ + type => integer, + description => <<"Number of sent UNSUBACK packet">>}, + 'packets.pingreq.received' => #{ + type => integer, + description => <<"Number of received PINGREQ packet">>}, + 'packets.pingresp.sent' => #{ + type => integer, + description => <<"Number of sent PUBRESP packet">>}, + 'packets.disconnect.received' => #{ + type => integer, + description => <<"Number of received DISCONNECT packet">>}, + 'packets.disconnect.sent' => #{ + type => integer, + description => <<"Number of sent DISCONNECT packet">>}, + 'packets.auth.received' => #{ + type => integer, + description => <<"Number of received AUTH packet">>}, + 'packets.auth.sent' => #{ + type => integer, + description => <<"Number of sent AUTH packet">>}, + 'rules.matched' => #{ + type => integer, + description => <<"Number of rule matched">>}, + 'session.created' => #{ + type => integer, + description => <<"Number of sessions created">>}, + 'session.discarded' => #{ + type => integer, + description => <<"Number of sessions dropped because Clean Session or Clean Start is true">>}, + 'session.resumed' => #{ + type => integer, + description => <<"Number of sessions resumed because Clean Session or Clean Start is false">>}, + 'session.takeovered' => #{ + type => integer, + description => <<"Number of sessions takeovered because Clean Session or Clean Start is false">>}, + 'session.terminated' => #{ + type => integer, + description => <<"Number of terminated sessions">>} + } + } + }. metrics_api() -> Metadata = #{ get => #{ description => "EMQ X metrics", responses => #{ - <<"200">> => #{ - schema => cowboy_swagger:schema(<<"metrics">>)}}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"List all metrics">>, <<"metrics">>)}}}, {"/metrics", Metadata, list}. %%%============================================================================================== diff --git a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl index 1aaecffdc..e3b062c7b 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_nodes.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_nodes.erl @@ -41,71 +41,71 @@ schemas() -> [node_schema()]. node_schema() -> - DefinitionName = <<"node">>, - DefinitionProperties = #{ - <<"node">> => #{ - type => <<"string">>, - description => <<"Node name">>}, - <<"connections">> => #{ - type => <<"integer">>, - description => <<"Number of clients currently connected to this node">>}, - <<"load1">> => #{ - type => <<"string">>, - description => <<"CPU average load in 1 minute">>}, - <<"load5">> => #{ - type => <<"string">>, - description => <<"CPU average load in 5 minute">>}, - <<"load15">> => #{ - type => <<"string">>, - description => <<"CPU average load in 15 minute">>}, - <<"max_fds">> => #{ - type => <<"integer">>, - description => <<"Maximum file descriptor limit for the operating system">>}, - <<"memory_total">> => #{ - type => <<"string">>, - description => <<"VM allocated system memory">>}, - <<"memory_used">> => #{ - type => <<"string">>, - description => <<"VM occupied system memory">>}, - <<"node_status">> => #{ - type => <<"string">>, - description => <<"Node status">>}, - <<"otp_release">> => #{ - type => <<"string">>, - description => <<"Erlang/OTP version used by EMQ X Broker">>}, - <<"process_available">> => #{ - type => <<"integer">>, - description => <<"Number of available processes">>}, - <<"process_used">> => #{ - type => <<"integer">>, - description => <<"Number of used processes">>}, - <<"uptime">> => #{ - type => <<"string">>, - description => <<"EMQ X Broker runtime">>}, - <<"version">> => #{ - type => <<"string">>, - description => <<"EMQ X Broker version">>}, - <<"sys_path">> => #{ - type => <<"string">>, - description => <<"EMQ X system file location">>}, - <<"log_path">> => #{ - type => <<"string">>, - description => <<"EMQ X log file location">>}, - <<"config_path">> => #{ - type => <<"string">>, - description => <<"EMQ X config file location">>} - }, - {DefinitionName, DefinitionProperties}. + #{ + node => #{ + type => object, + properties => #{ + node => #{ + type => string, + description => <<"Node name">>}, + connections => #{ + type => integer, + description => <<"Number of clients currently connected to this node">>}, + load1 => #{ + type => string, + description => <<"CPU average load in 1 minute">>}, + load5 => #{ + type => string, + description => <<"CPU average load in 5 minute">>}, + load15 => #{ + type => string, + description => <<"CPU average load in 15 minute">>}, + max_fds => #{ + type => integer, + description => <<"Maximum file descriptor limit for the operating system">>}, + memory_total => #{ + type => string, + description => <<"VM allocated system memory">>}, + memory_used => #{ + type => string, + description => <<"VM occupied system memory">>}, + node_status => #{ + type => string, + description => <<"Node status">>}, + otp_release => #{ + type => string, + description => <<"Erlang/OTP version used by EMQ X Broker">>}, + process_available => #{ + type => integer, + description => <<"Number of available processes">>}, + process_used => #{ + type => integer, + description => <<"Number of used processes">>}, + uptime => #{ + type => string, + description => <<"EMQ X Broker runtime">>}, + version => #{ + type => string, + description => <<"EMQ X Broker version">>}, + sys_path => #{ + type => string, + description => <<"EMQ X system file location">>}, + log_path => #{ + type => string, + description => <<"EMQ X log file location">>}, + config_path => #{ + type => string, + description => <<"EMQ X config file location">>} + } + } + }. nodes_api() -> Metadata = #{ get => #{ description => "List EMQ X nodes", responses => #{ - <<"200">> => #{description => <<"List EMQ X Nodes">>, - schema => #{ - type => array, - items => cowboy_swagger:schema(<<"node">>)}}}}}, + <<"200">> => emqx_mgmt_util:response_array_schema(<<"List EMQ X Nodes">>, <<"node">>)}}}, {"/nodes", Metadata, nodes}. node_api() -> @@ -116,15 +116,12 @@ node_api() -> name => node_name, in => path, description => "node name", - type => string, + schema => #{type => string}, required => true, - default => node()}], + example => node()}], responses => #{ - <<"400">> => - emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), - <<"200">> => #{ - description => <<"Get EMQ X Nodes info by name">>, - schema => cowboy_swagger:schema(<<"node">>)}}}}, + <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), + <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Nodes info by name">>, <<"node">>)}}}, {"/nodes/:node_name", Metadata, node}. node_metrics_api() -> @@ -135,15 +132,12 @@ node_metrics_api() -> name => node_name, in => path, description => "node name", - type => string, + schema => #{type => string}, required => true, - default => node()}], + example => node()}], responses => #{ - <<"400">> => - emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), - <<"200">> => #{ - description => <<"Get EMQ X Node Metrics">>, - schema => cowboy_swagger:schema(<<"metrics">>)}}}}, + <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), + <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Node Metrics">>, <<"metrics">>)}}}, {"/nodes/:node_name/metrics", Metadata, node_metrics}. node_stats_api() -> @@ -154,15 +148,12 @@ node_stats_api() -> name => node_name, in => path, description => "node name", - type => string, + schema => #{type => string}, required => true, - default => node()}], + example => node()}], responses => #{ - <<"400">> => - emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), - <<"200">> => #{ - description => <<"Get EMQ X Node Stats">>, - schema => cowboy_swagger:schema(<<"stats">>)}}}}, + <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), + <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Node Stats">>, <<"stats">>)}}}, {"/nodes/:node_name/stats", Metadata, node_metrics}. %%%============================================================================================== diff --git a/apps/emqx_management/src/emqx_mgmt_api_publish.erl b/apps/emqx_management/src/emqx_mgmt_api_publish.erl index a3305bc55..30fc9beab 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_publish.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_publish.erl @@ -27,85 +27,83 @@ api_spec() -> { [publish_api(), publish_batch_api()], - [request_message_schema(), mqtt_message_schema()] + [message_schema()] }. publish_api() -> MeteData = #{ post => #{ description => "publish", - parameters => [#{ - name => message, - in => body, - required => true, - schema => minirest:ref(<<"request_message">>) - }], + 'requestBody' => #{ + content => #{ + 'application/json' => #{ + schema => #{ + type => object, + properties => maps:with([id], message_properties())}}}}, responses => #{ - <<"200">> => #{ - description => <<"publish ok">>, - schema => minirest:ref(<<"message">>)}}}}, + <<"200">> => emqx_mgmt_util:response_schema(<<"publish ok">>, <<"message">>)}}}, {"/publish", MeteData, publish}. publish_batch_api() -> MeteData = #{ post => #{ description => "publish", - parameters => [#{ - name => message, - in => body, - required => true, - schema =>#{ - type => array, - items => minirest:ref(<<"request_message">>)} - }], + 'requestBody' => #{ + content => #{ + 'application/json' => #{ + schema => #{ + type => array, + items => #{ + type => object, + properties => maps:with([id], message_properties())}}}}}, responses => #{ - <<"200">> => #{ - description => <<"publish result">>, - schema => #{ - type => array, - items => minirest:ref(<<"message">>)}}}}}, + <<"200">> => emqx_mgmt_util:response_array_schema(<<"publish ok">>, <<"message">>)}}}, {"/publish_batch", MeteData, publish_batch}. -request_message_schema() -> - {<<"request_message">>, maps:without([<<"id">>], message_def())}. - -mqtt_message_schema() -> - {<<"message">>, message_def()}. - -message_def() -> +message_schema() -> #{ - <<"id">> => #{ - type => <<"string">>, + message => #{ + type => object, + properties => message_properties() + } + }. + +message_properties() -> + #{ + id => #{ + type => string, description => <<"Message ID">>}, - <<"topic">> => #{ - type => <<"string">>, + topic => #{ + type => string, description => <<"Topic">>}, - <<"qos">> => #{ - type => <<"integer">>, + qos => #{ + type => integer, enum => [0, 1, 2], description => <<"Qos">>}, - <<"payload">> => #{ - type => <<"string">>, + payload => #{ + type => string, description => <<"Topic">>}, - <<"from">> => #{ - type => <<"string">>, + from => #{ + type => string, description => <<"Message from">>}, - <<"flag">> => #{ + flag => #{ type => <<"object">>, description => <<"Message flag">>, properties => #{ - <<"sys">> => #{ - type => <<"boolean">>, + sys => #{ + type => boolean, default => false, description => <<"System message flag, nullable, default false">>}, - <<"dup">> => #{ - type => <<"boolean">>, + dup => #{ + type => boolean, default => false, description => <<"Dup message flag, nullable, default false">>}, - <<"retain">> => #{ - type => <<"boolean">>, + retain => #{ + type => boolean, default => false, - description => <<"Retain message flag, nullable, default false">>}}} + description => <<"Retain message flag, nullable, default false">>} + } + } }. publish(post, Request) -> diff --git a/apps/emqx_management/src/emqx_mgmt_api_stats.erl b/apps/emqx_management/src/emqx_mgmt_api_stats.erl index 55c24189a..f06968f60 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_stats.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_stats.erl @@ -22,81 +22,84 @@ -export([list/2]). api_spec() -> - {stats_api(), stats_schema()}. + {[stats_api()], [stats_schema()]}. stats_schema() -> - DefinitionName = <<"stats">>, - DefinitionProperties = #{ - <<"connections.count">> => #{ - type => <<"integer">>, - description => <<"Number of current connections">>}, - <<"connections.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of connections">>}, - <<"channels.count">> => #{ - type => <<"integer">>, - description => <<"sessions.count">>}, - <<"channels.max">> => #{ - type => <<"integer">>, - description => <<"session.max">>}, - <<"sessions.count">> => #{ - type => <<"integer">>, - description => <<"Number of current sessions">>}, - <<"sessions.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of sessions">>}, - <<"topics.count">> => #{ - type => <<"integer">>, - description => <<"Number of current topics">>}, - <<"topics.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of topics">>}, - <<"suboptions.count">> => #{ - type => <<"integer">>, - description => <<"subscriptions.count">>}, - <<"suboptions.max">> => #{ - type => <<"integer">>, - description => <<"subscriptions.max">>}, - <<"subscribers.count">> => #{ - type => <<"integer">>, - description => <<"Number of current subscribers">>}, - <<"subscribers.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of subscribers">>}, - <<"subscriptions.count">> => #{ - type => <<"integer">>, - description => <<"Number of current subscriptions, including shared subscriptions">>}, - <<"subscriptions.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of subscriptions">>}, - <<"subscriptions.shared.count">> => #{ - type => <<"integer">>, - description => <<"Number of current shared subscriptions">>}, - <<"subscriptions.shared.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of shared subscriptions">>}, - <<"routes.count">> => #{ - type => <<"integer">>, - description => <<"Number of current routes">>}, - <<"routes.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of routes">>}, - <<"retained.count">> => #{ - type => <<"integer">>, - description => <<"Number of currently retained messages">>}, - <<"retained.max">> => #{ - type => <<"integer">>, - description => <<"Historical maximum number of retained messages">>}}, - [{DefinitionName, DefinitionProperties}]. + #{ + stats => #{ + type => object, + properties => #{ + 'connections.count' => #{ + type => integer, + description => <<"Number of current connections">>}, + 'connections.max' => #{ + type => integer, + description => <<"Historical maximum number of connections">>}, + 'channels.count' => #{ + type => integer, + description => <<"sessions.count">>}, + 'channels.max' => #{ + type => integer, + description => <<"session.max">>}, + 'sessions.count' => #{ + type => integer, + description => <<"Number of current sessions">>}, + 'sessions.max' => #{ + type => integer, + description => <<"Historical maximum number of sessions">>}, + 'topics.count' => #{ + type => integer, + description => <<"Number of current topics">>}, + 'topics.max' => #{ + type => integer, + description => <<"Historical maximum number of topics">>}, + 'suboptions.count' => #{ + type => integer, + description => <<"subscriptions.count">>}, + 'suboptions.max' => #{ + type => integer, + description => <<"subscriptions.max">>}, + 'subscribers.count' => #{ + type => integer, + description => <<"Number of current subscribers">>}, + 'subscribers.max' => #{ + type => integer, + description => <<"Historical maximum number of subscribers">>}, + 'subscriptions.count' => #{ + type => integer, + description => <<"Number of current subscriptions, including shared subscriptions">>}, + 'subscriptions.max' => #{ + type => integer, + description => <<"Historical maximum number of subscriptions">>}, + 'subscriptions.shared.count' => #{ + type => integer, + description => <<"Number of current shared subscriptions">>}, + 'subscriptions.shared.max' => #{ + type => integer, + description => <<"Historical maximum number of shared subscriptions">>}, + 'routes.count' => #{ + type => integer, + description => <<"Number of current routes">>}, + 'routes.max' => #{ + type => integer, + description => <<"Historical maximum number of routes">>}, + 'retained.count' => #{ + type => integer, + description => <<"Number of currently retained messages">>}, + 'retained.max' => #{ + type => integer, + description => <<"Historical maximum number of retained messages">>} + } + } + }. stats_api() -> Metadata = #{ get => #{ description => "EMQ X stats", responses => #{ - <<"200">> => #{ - schema => cowboy_swagger:schema(<<"stats">>)}}}}, - [{"/stats", Metadata, list}]. + <<"200">> => emqx_mgmt_util:response_schema(<<"List stats ok">>, <<"stats">>)}}}, + {"/stats", Metadata, list}. %%%============================================================================================== %% api apply diff --git a/apps/emqx_management/src/emqx_mgmt_http.erl b/apps/emqx_management/src/emqx_mgmt_http.erl index aae681fd5..e07a857e5 100644 --- a/apps/emqx_management/src/emqx_mgmt_http.erl +++ b/apps/emqx_management/src/emqx_mgmt_http.erl @@ -44,14 +44,16 @@ start_listener({Proto, Port, Options}) -> Authorization = {?MODULE, authorize_appid}, RanchOptions = ranch_opts(Port, Options), GlobalSpec = #{ - swagger => "2.0", + openapi => "3.0.0", info => #{title => "EMQ X API", version => "5.0.0"}, - basePath => ?BASE_PATH, - securityDefinitions => #{ - application => #{ - type => apiKey, - name => "authorization", - in => header}}}, + servers => [#{url => ?BASE_PATH}], + components => #{ + schemas => #{}, + securitySchemes => #{ + application => #{ + type => apiKey, + name => "authorization", + in => header}}}}, Minirest = #{ protocol => Proto, base_path => ?BASE_PATH, diff --git a/apps/emqx_management/src/emqx_mgmt_util.erl b/apps/emqx_management/src/emqx_mgmt_util.erl index 6ba7cb93a..ee0a9c6b1 100644 --- a/apps/emqx_management/src/emqx_mgmt_util.erl +++ b/apps/emqx_management/src/emqx_mgmt_util.erl @@ -24,7 +24,12 @@ , batch_operation/3 ]). --export([ not_found_schema/1 +-export([ request_body_schema/1 + , request_body_array_schema/1 + , response_schema/1 + , response_schema/2 + , response_array_schema/2 + , not_found_schema/1 , not_found_schema/2 , batch_response_schema/1]). @@ -84,24 +89,46 @@ urldecode(S) -> %%%============================================================================================== %% schema util + +request_body_array_schema(Schema) when is_map(Schema) -> + json_content_schema("", #{type => array, items => Schema}); +request_body_array_schema(Ref) when is_binary(Ref) -> + json_content_schema("", #{type => array, items => minirest:ref(Ref)}). + +request_body_schema(Schema) when is_map(Schema) -> + json_content_schema("", Schema); +request_body_schema(Ref) when is_binary(Ref) -> + json_content_schema("", minirest:ref(Ref)). + +response_array_schema(Description, Schema) when is_map(Schema) -> + json_content_schema(Description, #{type => array, items => Schema}); +response_array_schema(Description, Ref) when is_binary(Ref) -> + json_content_schema(Description, #{type => array, items => minirest:ref(Ref)}). + +response_schema(Description) -> + json_content_schema(Description). + +response_schema(Description, Schema) when is_map(Schema) -> + json_content_schema(Description, Schema); +response_schema(Description, Ref) when is_binary(Ref) -> + json_content_schema(Description, minirest:ref(Ref)). + not_found_schema(Description) -> not_found_schema(Description, ["RESOURCE_NOT_FOUND"]). not_found_schema(Description, Enum) -> - #{ - description => Description, - schema => #{ - type => object, - properties => #{ - code => #{ - type => string, - enum => Enum}, - reason => #{ - type => string}}} - }. + Schema = #{ + type => object, + properties => #{ + code => #{ + type => string, + enum => Enum}, + reason => #{ + type => string}}}, + json_content_schema(Description, Schema). -batch_response_schema(DefName) -> - #{ +batch_response_schema(DefName) when is_binary(DefName) -> + Schema = #{ type => object, properties => #{ success => #{ @@ -119,13 +146,23 @@ batch_response_schema(DefName) -> #{ data => minirest:ref(DefName), reason => #{ - type => <<"string">> - } - } - } - } - } - }. + type => <<"string">>}}}}}}, + json_content_schema("", Schema). + +json_content_schema(Description, Schema) -> + Content = + #{content => #{ + 'application/json' => #{ + schema => Schema}}}, + case Description of + "" -> + Content; + _ -> + maps:merge(#{description => Description}, Content) + end. + +json_content_schema(Description) -> + #{description => Description}. %%%============================================================================================== batch_operation(Module, Function, ArgsList) -> diff --git a/rebar.config b/rebar.config index f706bab2d..4cad496d6 100644 --- a/rebar.config +++ b/rebar.config @@ -51,7 +51,7 @@ , {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.3"}}} , {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.1"}}} , {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v4.0.1"}}} % TODO: delete when all apps moved to hocon - , {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.1.1"}}} + , {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.1.2"}}} , {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.1"}}} , {replayq, {git, "https://github.com/emqx/replayq", {tag, "0.3.2"}}} , {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}