feat: update to openapi 3.0.0

This commit is contained in:
DDDHuang 2021-07-16 18:43:53 +08:00 committed by turtleDeng
parent ed1cf33b9d
commit 92ae5663a6
8 changed files with 682 additions and 649 deletions

View File

@ -71,144 +71,152 @@ apis() ->
, subscribe_api()]. , subscribe_api()].
schemas() -> schemas() ->
ClientDef = #{ Client = #{
<<"node">> => #{ client => #{
type => <<"string">>, type => object,
description => <<"Name of the node to which the client is connected">>}, properties => #{
<<"clientid">> => #{ node => #{
type => <<"string">>, type => string,
description => <<"Client identifier">>}, description => <<"Name of the node to which the client is connected">>},
<<"username">> => #{ clientid => #{
type => <<"string">>, type => string,
description => <<"User name of client when connecting">>}, description => <<"Client identifier">>},
<<"proto_name">> => #{ username => #{
type => <<"string">>, type => string,
description => <<"Client protocol name">>}, description => <<"User name of client when connecting">>},
<<"proto_ver">> => #{ proto_name => #{
type => <<"integer">>, type => string,
description => <<"Protocol version used by the client">>}, description => <<"Client protocol name">>},
<<"ip_address">> => #{ proto_ver => #{
type => <<"string">>, type => integer,
description => <<"Client's IP address">>}, description => <<"Protocol version used by the client">>},
<<"is_bridge">> => #{ ip_address => #{
type => <<"boolean">>, type => string,
description => <<"Indicates whether the client is connectedvia bridge">>}, description => <<"Client's IP address">>},
<<"connected_at">> => #{ is_bridge => #{
type => <<"string">>, type => boolean,
description => <<"Client connection time">>}, description => <<"Indicates whether the client is connectedvia bridge">>},
<<"disconnected_at">> => #{ connected_at => #{
type => <<"string">>, type => string,
description => <<"Client offline time, This field is only valid and returned when connected is false">>}, description => <<"Client connection time">>},
<<"connected">> => #{ disconnected_at => #{
type => <<"boolean">>, type => string,
description => <<"Whether the client is connected">>}, description => <<"Client offline time, This field is only valid and returned when connected is false">>},
<<"will_msg">> => #{ connected => #{
type => <<"string">>, type => boolean,
description => <<"Client will message">>}, description => <<"Whether the client is connected">>},
<<"zone">> => #{ will_msg => #{
type => <<"string">>, type => string,
description => <<"Indicate the configuration group used by the client">>}, description => <<"Client will message">>},
<<"keepalive">> => #{ zone => #{
type => <<"integer">>, type => string,
description => <<"keepalive time, with the unit of second">>}, description => <<"Indicate the configuration group used by the client">>},
<<"clean_start">> => #{ keepalive => #{
type => <<"boolean">>, type => integer,
description => <<"Indicate whether the client is using a brand new session">>}, description => <<"keepalive time, with the unit of second">>},
<<"expiry_interval">> => #{ clean_start => #{
type => <<"integer">>, type => boolean,
description => <<"Session expiration interval, with the unit of second">>}, description => <<"Indicate whether the client is using a brand new session">>},
<<"created_at">> => #{ expiry_interval => #{
type => <<"string">>, type => integer,
description => <<"Session creation time">>}, description => <<"Session expiration interval, with the unit of second">>},
<<"subscriptions_cnt">> => #{ created_at => #{
type => <<"integer">>, type => string,
description => <<"Number of subscriptions established by this client.">>}, description => <<"Session creation time">>},
<<"subscriptions_max">> => #{ subscriptions_cnt => #{
type => <<"integer">>, type => integer,
description => <<"v4 api name [max_subscriptions] Maximum number of subscriptions allowed by this client">>}, description => <<"Number of subscriptions established by this client.">>},
<<"inflight_cnt">> => #{ subscriptions_max => #{
type => <<"integer">>, type => integer,
description => <<"Current length of inflight">>}, description => <<"v4 api name [max_subscriptions] Maximum number of subscriptions allowed by this client">>},
<<"inflight_max">> => #{ inflight_cnt => #{
type => <<"integer">>, type => integer,
description => <<"v4 api name [max_inflight]. Maximum length of inflight">>}, description => <<"Current length of inflight">>},
<<"mqueue_len">> => #{ inflight_max => #{
type => <<"integer">>, type => integer,
description => <<"Current length of message queue">>}, description => <<"v4 api name [max_inflight]. Maximum length of inflight">>},
<<"mqueue_max">> => #{ mqueue_len => #{
type => <<"integer">>, type => integer,
description => <<"v4 api name [max_mqueue]. Maximum length of message queue">>}, description => <<"Current length of message queue">>},
<<"mqueue_dropped">> => #{ mqueue_max => #{
type => <<"integer">>, type => integer,
description => <<"Number of messages dropped by the message queue due to exceeding the length">>}, description => <<"v4 api name [max_mqueue]. Maximum length of message queue">>},
<<"awaiting_rel_cnt">> => #{ mqueue_dropped => #{
type => <<"integer">>, type => integer,
description => <<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>}, description => <<"Number of messages dropped by the message queue due to exceeding the length">>},
<<"awaiting_rel_max">> => #{ awaiting_rel_cnt => #{
type => <<"integer">>, type => integer,
description => <<"v4 api name [max_awaiting_rel]. Maximum allowed number of awaiting PUBREC packet">>}, description => <<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>},
<<"recv_oct">> => #{ awaiting_rel_max => #{
type => <<"integer">>, type => integer,
description => <<"Number of bytes received by EMQ X Broker (the same below)">>}, description => <<"v4 api name [max_awaiting_rel]. Maximum allowed number of awaiting PUBREC packet">>},
<<"recv_cnt">> => #{ recv_oct => #{
type => <<"integer">>, type => integer,
description => <<"Number of TCP packets received">>}, description => <<"Number of bytes received by EMQ X Broker (the same below)">>},
<<"recv_pkt">> => #{ recv_cnt => #{
type => <<"integer">>, type => integer,
description => <<"Number of MQTT packets received">>}, description => <<"Number of TCP packets received">>},
<<"recv_msg">> => #{ recv_pkt => #{
type => <<"integer">>, type => integer,
description => <<"Number of PUBLISH packets received">>}, description => <<"Number of MQTT packets received">>},
<<"send_oct">> => #{ recv_msg => #{
type => <<"integer">>, type => integer,
description => <<"Number of bytes sent">>}, description => <<"Number of PUBLISH packets received">>},
<<"send_cnt">> => #{ send_oct => #{
type => <<"integer">>, type => integer,
description => <<"Number of TCP packets sent">>}, description => <<"Number of bytes sent">>},
<<"send_pkt">> => #{ send_cnt => #{
type => <<"integer">>, type => integer,
description => <<"Number of MQTT packets sent">>}, description => <<"Number of TCP packets sent">>},
<<"send_msg">> => #{ send_pkt => #{
type => <<"integer">>, type => integer,
description => <<"Number of PUBLISH packets sent">>}, description => <<"Number of MQTT packets sent">>},
<<"mailbox_len">> => #{ send_msg => #{
type => <<"integer">>, type => integer,
description => <<"Process mailbox size">>}, description => <<"Number of PUBLISH packets sent">>},
<<"heap_size">> => #{ mailbox_len => #{
type => <<"integer">>, type => integer,
description => <<"Process heap size with the unit of byte">> description => <<"Process mailbox size">>},
}, heap_size => #{
<<"reductions">> => #{ type => integer,
type => <<"integer">>, description => <<"Process heap size with the unit of byte">>
description => <<"Erlang reduction">>}}, },
ACLCacheDefinitionProperties = #{ reductions => #{
<<"topic">> => #{ type => integer,
type => <<"string">>, description => <<"Erlang reduction">>}
description => <<"Topic name">>}, }
<<"access">> => #{ }
type => <<"string">>, },
enum => [<<"subscribe">>, <<"publish">>], AclCache = #{
description => <<"Access type">>}, acl_cache => #{
<<"result">> => #{ type => object,
type => <<"string">>, properties => #{
enum => [<<"allow">>, <<"deny">>], topic => #{
default => <<"allow">>, type => string,
description => <<"Allow or deny">>}, description => <<"Topic name">>},
<<"updated_time">> => #{ access => #{
type => <<"integer">>, type => string,
description => <<"Update time">>}}, enum => [<<"subscribe">>, <<"publish">>],
[{<<"client">>, ClientDef}, {<<"acl_cache">>, ACLCacheDefinitionProperties}]. 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() -> clients_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "List clients", description => "List clients",
responses => #{ responses => #{
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_array_schema(<<"List clients 200 OK">>, <<"client">>)}}},
description => <<"List clients 200 OK">>,
schema => #{
type => array,
items => minirest:ref(<<"client">>)}}}}},
{"/clients", Metadata, clients}. {"/clients", Metadata, clients}.
client_api() -> client_api() ->
@ -218,25 +226,23 @@ client_api() ->
parameters => [#{ parameters => [#{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456}], example => 123456}],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>),
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"List clients 200 OK">>, <<"client">>)}},
description => <<"Get clients 200 OK">>,
schema => minirest:ref(<<"client">>)}}},
delete => #{ delete => #{
description => "Kick out client by client ID", description => "Kick out client by client ID",
parameters => [#{ parameters => [#{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456}], example => 123456}],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), <<"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/:clientid", Metadata, client}.
clients_acl_cache_api() -> clients_acl_cache_api() ->
@ -246,26 +252,23 @@ clients_acl_cache_api() ->
parameters => [#{ parameters => [#{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456}], example => 123456}],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>),
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"List clients 200 OK">>, <<"acl_cache">>)}},
description => <<"List 200 OK">>,
schema => minirest:ref(<<"acl_cache">>)}}},
delete => #{ delete => #{
description => "Clean client acl cache", description => "Clean client acl cache",
parameters => [#{ parameters => [#{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456}], example => 123456}],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"client id not found">>), <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>),
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"Delete clients 200 OK">>)}}},
description => <<"Clean acl cache 200 OK">>}}}},
{"/clients/:clientid/acl_cache", Metadata, acl_cache}. {"/clients/:clientid/acl_cache", Metadata, acl_cache}.
subscribe_api() -> subscribe_api() ->
@ -276,51 +279,47 @@ subscribe_api() ->
#{ #{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456 example => 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">>}}}
} }
], ],
'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 => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), <<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>),
<<"200">> => #{description => <<"subscribe ok">>}}}, <<"200">> => emqx_mgmt_util:response_schema(<<"subscribe ok">>)}},
delete => #{ delete => #{
description => "unsubscribe", description => "unsubscribe",
parameters => [ parameters => [
#{ #{
name => clientid, name => clientid,
in => path, in => path,
type => string, schema => #{type => string},
required => true, required => true,
default => 123456 example => 123456
}, },
#{ #{
name => topic, name => topic,
in => query, in => query,
type => string, schema => #{type => string},
required => true, required => true,
default => <<"topic_1">> example => <<"topic_1">>
} }
], ],
responses => #{ responses => #{
<<"404">> => emqx_mgmt_util:not_found_schema(<<"Client id not found">>), <<"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}. {"/clients/:clientid/subscribe", Metadata, subscribe}.
%%%============================================================================================== %%%==============================================================================================

View File

@ -26,263 +26,266 @@ api_spec() ->
{[metrics_api()], [metrics_schema()]}. {[metrics_api()], [metrics_schema()]}.
metrics_schema() -> metrics_schema() ->
DefinitionName = <<"metrics">>, #{
DefinitionProperties = #{ metrics => #{
<<"actions.failure">> => #{ type => object,
type => <<"integer">>, properties => #{
description => <<"Number of failure executions of the rule engine action">>}, 'actions.failure' => #{
<<"actions.success">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of failure executions of the rule engine action">>},
description => <<"Number of successful executions of the rule engine action">>}, 'actions.success' => #{
<<"bytes.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of successful executions of the rule engine action">>},
description => <<"Number of bytes received by EMQ X Broker">>}, 'bytes.received' => #{
<<"bytes.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of bytes received by EMQ X Broker">>},
description => <<"Number of bytes sent by EMQ X Broker on this connection">>}, 'bytes.sent' => #{
<<"client.authenticate">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of bytes sent by EMQ X Broker on this connection">>},
description => <<"Number of client authentications">>}, 'client.authenticate' => #{
<<"client.auth.anonymous">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of client authentications">>},
description => <<"Number of clients who log in anonymously">>}, 'client.auth.anonymous' => #{
<<"client.connect">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of clients who log in anonymously">>},
description => <<"Number of client connections">>}, 'client.connect' => #{
<<"client.connack">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of client connections">>},
description => <<"Number of CONNACK packet sent">>}, 'client.connack' => #{
<<"client.connected">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of CONNACK packet sent">>},
description => <<"Number of successful client connections">>}, 'client.connected' => #{
<<"client.disconnected">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of successful client connections">>},
description => <<"Number of client disconnects">>}, 'client.disconnected' => #{
<<"client.check_acl">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of client disconnects">>},
description => <<"Number of ACL rule checks">>}, 'client.check_acl' => #{
<<"client.subscribe">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of ACL rule checks">>},
description => <<"Number of client subscriptions">>}, 'client.subscribe' => #{
<<"client.unsubscribe">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of client subscriptions">>},
description => <<"Number of client unsubscriptions">>}, 'client.unsubscribe' => #{
<<"delivery.dropped.too_large">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of client unsubscriptions">>},
description => <<"The number of messages that were dropped because the length exceeded the limit when sending">>}, 'delivery.dropped.too_large' => #{
<<"delivery.dropped.queue_full">> => #{ type => integer,
type => <<"integer">>, description => <<"The number of messages that were dropped because the length exceeded the limit when sending">>},
description => <<"Number of messages with a non-zero QoS that were dropped because the message queue was full when sending">>}, 'delivery.dropped.queue_full' => #{
<<"delivery.dropped.qos0_msg">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages with a non-zero QoS that were dropped because the message queue was full when sending">>},
description => <<"Number of messages with QoS 0 that were dropped because the message queue was full when sending">>}, 'delivery.dropped.qos0_msg' => #{
<<"delivery.dropped.expired">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages with QoS 0 that were dropped because the message queue was full when sending">>},
description => <<"Number of messages dropped due to message expiration on sending">>}, 'delivery.dropped.expired' => #{
<<"delivery.dropped.no_local">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages dropped due to message expiration on sending">>},
description => <<"Number of messages that were dropped due to the No Local subscription option when sending">>}, 'delivery.dropped.no_local' => #{
<<"delivery.dropped">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages that were dropped due to the No Local subscription option when sending">>},
description => <<"Total number of discarded messages when sending">>}, 'delivery.dropped' => #{
<<"messages.delayed">> => #{ type => integer,
type => <<"integer">>, description => <<"Total number of discarded messages when sending">>},
description => <<"Number of delay- published messages stored by EMQ X Broker">>}, 'messages.delayed' => #{
<<"messages.delivered">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of delay- published messages stored by EMQ X Broker">>},
description => <<"Number of messages forwarded to the subscription process internally by EMQ X Broker">>}, 'messages.delivered' => #{
<<"messages.dropped">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages forwarded to the subscription process internally by EMQ X Broker">>},
description => <<"Total number of messages dropped by EMQ X Broker before forwarding to the subscription process">>}, 'messages.dropped' => #{
<<"messages.dropped.expired">> => #{ type => integer,
type => <<"integer">>, description => <<"Total number of messages dropped by EMQ X Broker before forwarding to the subscription process">>},
description => <<"Number of messages dropped due to message expiration when receiving">>}, 'messages.dropped.expired' => #{
<<"messages.dropped.no_subscribers">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages dropped due to message expiration when receiving">>},
description => <<"Number of messages dropped due to no subscribers">>}, 'messages.dropped.no_subscribers' => #{
<<"messages.forward">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages dropped due to no subscribers">>},
description => <<"Number of messages forwarded to other nodes">>}, 'messages.forward' => #{
<<"messages.publish">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages forwarded to other nodes">>},
description => <<"Number of messages published in addition to system messages">>}, 'messages.publish' => #{
<<"messages.qos0.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages published in addition to system messages">>},
description => <<"Number of QoS 0 messages received from clients">>}, 'messages.qos0.received' => #{
<<"messages.qos1.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 0 messages received from clients">>},
description => <<"Number of QoS 1 messages received from clients">>}, 'messages.qos1.received' => #{
<<"messages.qos2.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 1 messages received from clients">>},
description => <<"Number of QoS 2 messages received from clients">>}, 'messages.qos2.received' => #{
<<"messages.qos0.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 2 messages received from clients">>},
description => <<"Number of QoS 0 messages sent to clients">>}, 'messages.qos0.sent' => #{
<<"messages.qos1.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 0 messages sent to clients">>},
description => <<"Number of QoS 1 messages sent to clients">>}, 'messages.qos1.sent' => #{
<<"messages.qos2.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 1 messages sent to clients">>},
description => <<"Number of QoS 2 messages sent to clients">>}, 'messages.qos2.sent' => #{
<<"messages.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of QoS 2 messages sent to clients">>},
description => <<"Number of messages received from the client, equal to the sum of messages.qos0.receivedmessages.qos1.received and messages.qos2.received">>}, 'messages.received' => #{
<<"messages.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages received from the client, equal to the sum of messages.qos0.receivedmessages.qos1.received and messages.qos2.received">>},
description => <<"Number of messages sent to the client, equal to the sum of messages.qos0.sentmessages.qos1.sent and messages.qos2.sent">>}, 'messages.sent' => #{
<<"messages.retained">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages sent to the client, equal to the sum of messages.qos0.sentmessages.qos1.sent and messages.qos2.sent">>},
description => <<"Number of retained messages stored by EMQ X Broker">>}, 'messages.retained' => #{
<<"messages.acked">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of retained messages stored by EMQ X Broker">>},
description => <<"Number of received PUBACK and PUBREC packet">>}, 'messages.acked' => #{
<<"packets.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBACK and PUBREC packet">>},
description => <<"Number of received packet">>}, 'packets.received' => #{
<<"packets.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received packet">>},
description => <<"Number of sent packet">>}, 'packets.sent' => #{
<<"packets.connect.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent packet">>},
description => <<"Number of received CONNECT packet">>}, 'packets.connect.received' => #{
<<"packets.connack.auth_error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received CONNECT packet">>},
description => <<"Number of received CONNECT packet with failed authentication">>}, 'packets.connack.auth_error' => #{
<<"packets.connack.error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received CONNECT packet with failed authentication">>},
description => <<"Number of received CONNECT packet with unsuccessful connections">>}, 'packets.connack.error' => #{
<<"packets.connack.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received CONNECT packet with unsuccessful connections">>},
description => <<"Number of sent CONNACK packet">>}, 'packets.connack.sent' => #{
<<"packets.publish.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent CONNACK packet">>},
description => <<"Number of received PUBLISH packet">>}, 'packets.publish.received' => #{
<<"packets.publish.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBLISH packet">>},
description => <<"Number of sent PUBLISH packet">>}, 'packets.publish.sent' => #{
<<"packets.publish.inuse">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBLISH packet">>},
description => <<"Number of received PUBLISH packet with occupied identifiers">>}, 'packets.publish.inuse' => #{
<<"packets.publish.auth_error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBLISH packet with occupied identifiers">>},
description => <<"Number of received PUBLISH packets with failed the ACL check">>}, 'packets.publish.auth_error' => #{
<<"packets.publish.error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBLISH packets with failed the ACL check">>},
description => <<"Number of received PUBLISH packet that cannot be published">>}, 'packets.publish.error' => #{
<<"packets.publish.dropped">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBLISH packet that cannot be published">>},
description => <<"Number of messages discarded due to the receiving limit">>}, 'packets.publish.dropped' => #{
<<"packets.puback.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of messages discarded due to the receiving limit">>},
description => <<"Number of received PUBACK packet">>}, 'packets.puback.received' => #{
<<"packets.puback.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBACK packet">>},
description => <<"Number of sent PUBACK packet">>}, 'packets.puback.sent' => #{
<<"packets.puback.inuse">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBACK packet">>},
description => <<"Number of received PUBACK packet with occupied identifiers">>}, 'packets.puback.inuse' => #{
<<"packets.puback.missed">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBACK packet with occupied identifiers">>},
description => <<"Number of received packet with identifiers.">>}, 'packets.puback.missed' => #{
<<"packets.pubrec.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received packet with identifiers.">>},
description => <<"Number of received PUBREC packet">>}, 'packets.pubrec.received' => #{
<<"packets.pubrec.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBREC packet">>},
description => <<"Number of sent PUBREC packet">>}, 'packets.pubrec.sent' => #{
<<"packets.pubrec.inuse">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBREC packet">>},
description => <<"Number of received PUBREC packet with occupied identifiers">>}, 'packets.pubrec.inuse' => #{
<<"packets.pubrec.missed">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBREC packet with occupied identifiers">>},
description => <<"Number of received PUBREC packet with unknown identifiers">>}, 'packets.pubrec.missed' => #{
<<"packets.pubrel.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBREC packet with unknown identifiers">>},
description => <<"Number of received PUBREL packet">>}, 'packets.pubrel.received' => #{
<<"packets.pubrel.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBREL packet">>},
description => <<"Number of sent PUBREL packet">>}, 'packets.pubrel.sent' => #{
<<"packets.pubrel.missed">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBREL packet">>},
description => <<"Number of received PUBREC packet with unknown identifiers">>}, 'packets.pubrel.missed' => #{
<<"packets.pubcomp.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBREC packet with unknown identifiers">>},
description => <<"Number of received PUBCOMP packet">>}, 'packets.pubcomp.received' => #{
<<"packets.pubcomp.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBCOMP packet">>},
description => <<"Number of sent PUBCOMP packet">>}, 'packets.pubcomp.sent' => #{
<<"packets.pubcomp.inuse">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBCOMP packet">>},
description => <<"Number of received PUBCOMP packet with occupied identifiers">>}, 'packets.pubcomp.inuse' => #{
<<"packets.pubcomp.missed">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PUBCOMP packet with occupied identifiers">>},
description => <<"Number of missed PUBCOMP packet">>}, 'packets.pubcomp.missed' => #{
<<"packets.subscribe.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of missed PUBCOMP packet">>},
description => <<"Number of received SUBSCRIBE packet">>}, 'packets.subscribe.received' => #{
<<"packets.subscribe.error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received SUBSCRIBE packet">>},
description => <<"Number of received SUBSCRIBE packet with failed subscriptions">>}, 'packets.subscribe.error' => #{
<<"packets.subscribe.auth_error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received SUBSCRIBE packet with failed subscriptions">>},
description => <<"Number of received SUBACK packet with failed ACL check">>}, 'packets.subscribe.auth_error' => #{
<<"packets.suback.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received SUBACK packet with failed ACL check">>},
description => <<"Number of sent SUBACK packet">>}, 'packets.suback.sent' => #{
<<"packets.unsubscribe.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent SUBACK packet">>},
description => <<"Number of received UNSUBSCRIBE packet">>}, 'packets.unsubscribe.received' => #{
<<"packets.unsubscribe.error">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received UNSUBSCRIBE packet">>},
description => <<"Number of received UNSUBSCRIBE packet with failed unsubscriptions">>}, 'packets.unsubscribe.error' => #{
<<"packets.unsuback.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received UNSUBSCRIBE packet with failed unsubscriptions">>},
description => <<"Number of sent UNSUBACK packet">>}, 'packets.unsuback.sent' => #{
<<"packets.pingreq.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent UNSUBACK packet">>},
description => <<"Number of received PINGREQ packet">>}, 'packets.pingreq.received' => #{
<<"packets.pingresp.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received PINGREQ packet">>},
description => <<"Number of sent PUBRESP packet">>}, 'packets.pingresp.sent' => #{
<<"packets.disconnect.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent PUBRESP packet">>},
description => <<"Number of received DISCONNECT packet">>}, 'packets.disconnect.received' => #{
<<"packets.disconnect.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received DISCONNECT packet">>},
description => <<"Number of sent DISCONNECT packet">>}, 'packets.disconnect.sent' => #{
<<"packets.auth.received">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent DISCONNECT packet">>},
description => <<"Number of received AUTH packet">>}, 'packets.auth.received' => #{
<<"packets.auth.sent">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of received AUTH packet">>},
description => <<"Number of sent AUTH packet">>}, 'packets.auth.sent' => #{
<<"rules.matched">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sent AUTH packet">>},
description => <<"Number of rule matched">>}, 'rules.matched' => #{
<<"session.created">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of rule matched">>},
description => <<"Number of sessions created">>}, 'session.created' => #{
<<"session.discarded">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sessions created">>},
description => <<"Number of sessions dropped because Clean Session or Clean Start is true">>}, 'session.discarded' => #{
<<"session.resumed">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sessions dropped because Clean Session or Clean Start is true">>},
description => <<"Number of sessions resumed because Clean Session or Clean Start is false">>}, 'session.resumed' => #{
<<"session.takeovered">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sessions resumed because Clean Session or Clean Start is false">>},
description => <<"Number of sessions takeovered because Clean Session or Clean Start is false">>}, 'session.takeovered' => #{
<<"session.terminated">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of sessions takeovered because Clean Session or Clean Start is false">>},
description => <<"Number of terminated sessions">>}}, 'session.terminated' => #{
{DefinitionName, DefinitionProperties}. type => integer,
description => <<"Number of terminated sessions">>}
}
}
}.
metrics_api() -> metrics_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "EMQ X metrics", description => "EMQ X metrics",
responses => #{ responses => #{
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"List all metrics">>, <<"metrics">>)}}},
schema => cowboy_swagger:schema(<<"metrics">>)}}}},
{"/metrics", Metadata, list}. {"/metrics", Metadata, list}.
%%%============================================================================================== %%%==============================================================================================

View File

@ -41,71 +41,71 @@ schemas() ->
[node_schema()]. [node_schema()].
node_schema() -> node_schema() ->
DefinitionName = <<"node">>, #{
DefinitionProperties = #{ node => #{
<<"node">> => #{ type => object,
type => <<"string">>, properties => #{
description => <<"Node name">>}, node => #{
<<"connections">> => #{ type => string,
type => <<"integer">>, description => <<"Node name">>},
description => <<"Number of clients currently connected to this node">>}, connections => #{
<<"load1">> => #{ type => integer,
type => <<"string">>, description => <<"Number of clients currently connected to this node">>},
description => <<"CPU average load in 1 minute">>}, load1 => #{
<<"load5">> => #{ type => string,
type => <<"string">>, description => <<"CPU average load in 1 minute">>},
description => <<"CPU average load in 5 minute">>}, load5 => #{
<<"load15">> => #{ type => string,
type => <<"string">>, description => <<"CPU average load in 5 minute">>},
description => <<"CPU average load in 15 minute">>}, load15 => #{
<<"max_fds">> => #{ type => string,
type => <<"integer">>, description => <<"CPU average load in 15 minute">>},
description => <<"Maximum file descriptor limit for the operating system">>}, max_fds => #{
<<"memory_total">> => #{ type => integer,
type => <<"string">>, description => <<"Maximum file descriptor limit for the operating system">>},
description => <<"VM allocated system memory">>}, memory_total => #{
<<"memory_used">> => #{ type => string,
type => <<"string">>, description => <<"VM allocated system memory">>},
description => <<"VM occupied system memory">>}, memory_used => #{
<<"node_status">> => #{ type => string,
type => <<"string">>, description => <<"VM occupied system memory">>},
description => <<"Node status">>}, node_status => #{
<<"otp_release">> => #{ type => string,
type => <<"string">>, description => <<"Node status">>},
description => <<"Erlang/OTP version used by EMQ X Broker">>}, otp_release => #{
<<"process_available">> => #{ type => string,
type => <<"integer">>, description => <<"Erlang/OTP version used by EMQ X Broker">>},
description => <<"Number of available processes">>}, process_available => #{
<<"process_used">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of available processes">>},
description => <<"Number of used processes">>}, process_used => #{
<<"uptime">> => #{ type => integer,
type => <<"string">>, description => <<"Number of used processes">>},
description => <<"EMQ X Broker runtime">>}, uptime => #{
<<"version">> => #{ type => string,
type => <<"string">>, description => <<"EMQ X Broker runtime">>},
description => <<"EMQ X Broker version">>}, version => #{
<<"sys_path">> => #{ type => string,
type => <<"string">>, description => <<"EMQ X Broker version">>},
description => <<"EMQ X system file location">>}, sys_path => #{
<<"log_path">> => #{ type => string,
type => <<"string">>, description => <<"EMQ X system file location">>},
description => <<"EMQ X log file location">>}, log_path => #{
<<"config_path">> => #{ type => string,
type => <<"string">>, description => <<"EMQ X log file location">>},
description => <<"EMQ X config file location">>} config_path => #{
}, type => string,
{DefinitionName, DefinitionProperties}. description => <<"EMQ X config file location">>}
}
}
}.
nodes_api() -> nodes_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "List EMQ X nodes", description => "List EMQ X nodes",
responses => #{ responses => #{
<<"200">> => #{description => <<"List EMQ X Nodes">>, <<"200">> => emqx_mgmt_util:response_array_schema(<<"List EMQ X Nodes">>, <<"node">>)}}},
schema => #{
type => array,
items => cowboy_swagger:schema(<<"node">>)}}}}},
{"/nodes", Metadata, nodes}. {"/nodes", Metadata, nodes}.
node_api() -> node_api() ->
@ -116,15 +116,12 @@ node_api() ->
name => node_name, name => node_name,
in => path, in => path,
description => "node name", description => "node name",
type => string, schema => #{type => string},
required => true, required => true,
default => node()}], example => node()}],
responses => #{ responses => #{
<<"400">> => <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]),
emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Nodes info by name">>, <<"node">>)}}},
<<"200">> => #{
description => <<"Get EMQ X Nodes info by name">>,
schema => cowboy_swagger:schema(<<"node">>)}}}},
{"/nodes/:node_name", Metadata, node}. {"/nodes/:node_name", Metadata, node}.
node_metrics_api() -> node_metrics_api() ->
@ -135,15 +132,12 @@ node_metrics_api() ->
name => node_name, name => node_name,
in => path, in => path,
description => "node name", description => "node name",
type => string, schema => #{type => string},
required => true, required => true,
default => node()}], example => node()}],
responses => #{ responses => #{
<<"400">> => <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]),
emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Node Metrics">>, <<"metrics">>)}}},
<<"200">> => #{
description => <<"Get EMQ X Node Metrics">>,
schema => cowboy_swagger:schema(<<"metrics">>)}}}},
{"/nodes/:node_name/metrics", Metadata, node_metrics}. {"/nodes/:node_name/metrics", Metadata, node_metrics}.
node_stats_api() -> node_stats_api() ->
@ -154,15 +148,12 @@ node_stats_api() ->
name => node_name, name => node_name,
in => path, in => path,
description => "node name", description => "node name",
type => string, schema => #{type => string},
required => true, required => true,
default => node()}], example => node()}],
responses => #{ responses => #{
<<"400">> => <<"400">> => emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]),
emqx_mgmt_util:not_found_schema(<<"Node error">>, [<<"SOURCE_ERROR">>]), <<"200">> => emqx_mgmt_util:response_schema(<<"Get EMQ X Node Stats">>, <<"stats">>)}}},
<<"200">> => #{
description => <<"Get EMQ X Node Stats">>,
schema => cowboy_swagger:schema(<<"stats">>)}}}},
{"/nodes/:node_name/stats", Metadata, node_metrics}. {"/nodes/:node_name/stats", Metadata, node_metrics}.
%%%============================================================================================== %%%==============================================================================================

View File

@ -27,85 +27,83 @@
api_spec() -> api_spec() ->
{ {
[publish_api(), publish_batch_api()], [publish_api(), publish_batch_api()],
[request_message_schema(), mqtt_message_schema()] [message_schema()]
}. }.
publish_api() -> publish_api() ->
MeteData = #{ MeteData = #{
post => #{ post => #{
description => "publish", description => "publish",
parameters => [#{ 'requestBody' => #{
name => message, content => #{
in => body, 'application/json' => #{
required => true, schema => #{
schema => minirest:ref(<<"request_message">>) type => object,
}], properties => maps:with([id], message_properties())}}}},
responses => #{ responses => #{
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"publish ok">>, <<"message">>)}}},
description => <<"publish ok">>,
schema => minirest:ref(<<"message">>)}}}},
{"/publish", MeteData, publish}. {"/publish", MeteData, publish}.
publish_batch_api() -> publish_batch_api() ->
MeteData = #{ MeteData = #{
post => #{ post => #{
description => "publish", description => "publish",
parameters => [#{ 'requestBody' => #{
name => message, content => #{
in => body, 'application/json' => #{
required => true, schema => #{
schema =>#{ type => array,
type => array, items => #{
items => minirest:ref(<<"request_message">>)} type => object,
}], properties => maps:with([id], message_properties())}}}}},
responses => #{ responses => #{
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_array_schema(<<"publish ok">>, <<"message">>)}}},
description => <<"publish result">>,
schema => #{
type => array,
items => minirest:ref(<<"message">>)}}}}},
{"/publish_batch", MeteData, publish_batch}. {"/publish_batch", MeteData, publish_batch}.
request_message_schema() -> message_schema() ->
{<<"request_message">>, maps:without([<<"id">>], message_def())}.
mqtt_message_schema() ->
{<<"message">>, message_def()}.
message_def() ->
#{ #{
<<"id">> => #{ message => #{
type => <<"string">>, type => object,
properties => message_properties()
}
}.
message_properties() ->
#{
id => #{
type => string,
description => <<"Message ID">>}, description => <<"Message ID">>},
<<"topic">> => #{ topic => #{
type => <<"string">>, type => string,
description => <<"Topic">>}, description => <<"Topic">>},
<<"qos">> => #{ qos => #{
type => <<"integer">>, type => integer,
enum => [0, 1, 2], enum => [0, 1, 2],
description => <<"Qos">>}, description => <<"Qos">>},
<<"payload">> => #{ payload => #{
type => <<"string">>, type => string,
description => <<"Topic">>}, description => <<"Topic">>},
<<"from">> => #{ from => #{
type => <<"string">>, type => string,
description => <<"Message from">>}, description => <<"Message from">>},
<<"flag">> => #{ flag => #{
type => <<"object">>, type => <<"object">>,
description => <<"Message flag">>, description => <<"Message flag">>,
properties => #{ properties => #{
<<"sys">> => #{ sys => #{
type => <<"boolean">>, type => boolean,
default => false, default => false,
description => <<"System message flag, nullable, default false">>}, description => <<"System message flag, nullable, default false">>},
<<"dup">> => #{ dup => #{
type => <<"boolean">>, type => boolean,
default => false, default => false,
description => <<"Dup message flag, nullable, default false">>}, description => <<"Dup message flag, nullable, default false">>},
<<"retain">> => #{ retain => #{
type => <<"boolean">>, type => boolean,
default => false, default => false,
description => <<"Retain message flag, nullable, default false">>}}} description => <<"Retain message flag, nullable, default false">>}
}
}
}. }.
publish(post, Request) -> publish(post, Request) ->

View File

@ -22,81 +22,84 @@
-export([list/2]). -export([list/2]).
api_spec() -> api_spec() ->
{stats_api(), stats_schema()}. {[stats_api()], [stats_schema()]}.
stats_schema() -> stats_schema() ->
DefinitionName = <<"stats">>, #{
DefinitionProperties = #{ stats => #{
<<"connections.count">> => #{ type => object,
type => <<"integer">>, properties => #{
description => <<"Number of current connections">>}, 'connections.count' => #{
<<"connections.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current connections">>},
description => <<"Historical maximum number of connections">>}, 'connections.max' => #{
<<"channels.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of connections">>},
description => <<"sessions.count">>}, 'channels.count' => #{
<<"channels.max">> => #{ type => integer,
type => <<"integer">>, description => <<"sessions.count">>},
description => <<"session.max">>}, 'channels.max' => #{
<<"sessions.count">> => #{ type => integer,
type => <<"integer">>, description => <<"session.max">>},
description => <<"Number of current sessions">>}, 'sessions.count' => #{
<<"sessions.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current sessions">>},
description => <<"Historical maximum number of sessions">>}, 'sessions.max' => #{
<<"topics.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of sessions">>},
description => <<"Number of current topics">>}, 'topics.count' => #{
<<"topics.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current topics">>},
description => <<"Historical maximum number of topics">>}, 'topics.max' => #{
<<"suboptions.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of topics">>},
description => <<"subscriptions.count">>}, 'suboptions.count' => #{
<<"suboptions.max">> => #{ type => integer,
type => <<"integer">>, description => <<"subscriptions.count">>},
description => <<"subscriptions.max">>}, 'suboptions.max' => #{
<<"subscribers.count">> => #{ type => integer,
type => <<"integer">>, description => <<"subscriptions.max">>},
description => <<"Number of current subscribers">>}, 'subscribers.count' => #{
<<"subscribers.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current subscribers">>},
description => <<"Historical maximum number of subscribers">>}, 'subscribers.max' => #{
<<"subscriptions.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of subscribers">>},
description => <<"Number of current subscriptions, including shared subscriptions">>}, 'subscriptions.count' => #{
<<"subscriptions.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current subscriptions, including shared subscriptions">>},
description => <<"Historical maximum number of subscriptions">>}, 'subscriptions.max' => #{
<<"subscriptions.shared.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of subscriptions">>},
description => <<"Number of current shared subscriptions">>}, 'subscriptions.shared.count' => #{
<<"subscriptions.shared.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current shared subscriptions">>},
description => <<"Historical maximum number of shared subscriptions">>}, 'subscriptions.shared.max' => #{
<<"routes.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of shared subscriptions">>},
description => <<"Number of current routes">>}, 'routes.count' => #{
<<"routes.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of current routes">>},
description => <<"Historical maximum number of routes">>}, 'routes.max' => #{
<<"retained.count">> => #{ type => integer,
type => <<"integer">>, description => <<"Historical maximum number of routes">>},
description => <<"Number of currently retained messages">>}, 'retained.count' => #{
<<"retained.max">> => #{ type => integer,
type => <<"integer">>, description => <<"Number of currently retained messages">>},
description => <<"Historical maximum number of retained messages">>}}, 'retained.max' => #{
[{DefinitionName, DefinitionProperties}]. type => integer,
description => <<"Historical maximum number of retained messages">>}
}
}
}.
stats_api() -> stats_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "EMQ X stats", description => "EMQ X stats",
responses => #{ responses => #{
<<"200">> => #{ <<"200">> => emqx_mgmt_util:response_schema(<<"List stats ok">>, <<"stats">>)}}},
schema => cowboy_swagger:schema(<<"stats">>)}}}}, {"/stats", Metadata, list}.
[{"/stats", Metadata, list}].
%%%============================================================================================== %%%==============================================================================================
%% api apply %% api apply

View File

@ -44,14 +44,16 @@ start_listener({Proto, Port, Options}) ->
Authorization = {?MODULE, authorize_appid}, Authorization = {?MODULE, authorize_appid},
RanchOptions = ranch_opts(Port, Options), RanchOptions = ranch_opts(Port, Options),
GlobalSpec = #{ GlobalSpec = #{
swagger => "2.0", openapi => "3.0.0",
info => #{title => "EMQ X API", version => "5.0.0"}, info => #{title => "EMQ X API", version => "5.0.0"},
basePath => ?BASE_PATH, servers => [#{url => ?BASE_PATH}],
securityDefinitions => #{ components => #{
application => #{ schemas => #{},
type => apiKey, securitySchemes => #{
name => "authorization", application => #{
in => header}}}, type => apiKey,
name => "authorization",
in => header}}}},
Minirest = #{ Minirest = #{
protocol => Proto, protocol => Proto,
base_path => ?BASE_PATH, base_path => ?BASE_PATH,

View File

@ -24,7 +24,12 @@
, batch_operation/3 , 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 , not_found_schema/2
, batch_response_schema/1]). , batch_response_schema/1]).
@ -84,24 +89,46 @@ urldecode(S) ->
%%%============================================================================================== %%%==============================================================================================
%% schema util %% 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) ->
not_found_schema(Description, ["RESOURCE_NOT_FOUND"]). not_found_schema(Description, ["RESOURCE_NOT_FOUND"]).
not_found_schema(Description, Enum) -> not_found_schema(Description, Enum) ->
#{ Schema = #{
description => Description, type => object,
schema => #{ properties => #{
type => object, code => #{
properties => #{ type => string,
code => #{ enum => Enum},
type => string, reason => #{
enum => Enum}, type => string}}},
reason => #{ json_content_schema(Description, Schema).
type => string}}}
}.
batch_response_schema(DefName) -> batch_response_schema(DefName) when is_binary(DefName) ->
#{ Schema = #{
type => object, type => object,
properties => #{ properties => #{
success => #{ success => #{
@ -119,13 +146,23 @@ batch_response_schema(DefName) ->
#{ #{
data => minirest:ref(DefName), data => minirest:ref(DefName),
reason => #{ 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) -> batch_operation(Module, Function, ArgsList) ->

View File

@ -51,7 +51,7 @@
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.3"}}} , {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.10.3"}}}
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.1"}}} , {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 , {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"}}} , {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.1"}}}
, {replayq, {git, "https://github.com/emqx/replayq", {tag, "0.3.2"}}} , {replayq, {git, "https://github.com/emqx/replayq", {tag, "0.3.2"}}}
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}} , {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}