Merge pull request #10513 from zmstone/0424-EMQX-9689-stop-providing-desc-and-label-in-schemas-api

0424 emqx 9689 stop providing desc and label in schemas api (part 1)
This commit is contained in:
Zaiming (Stone) Shi 2023-04-26 19:04:33 +02:00 committed by GitHub
commit 75294a4f73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 382 additions and 145 deletions

View File

@ -194,15 +194,12 @@ jobs:
run: |
CID=$(docker run -d --rm -P $EMQX_IMAGE_TAG)
HTTP_PORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "18083/tcp") 0).HostPort}}' $CID)
export EMQX_SMOKE_TEST_CHECK_HIDDEN_FIELDS='yes'
./scripts/test/emqx-smoke-test.sh localhost $HTTP_PORT
docker stop $CID
- name: test two nodes cluster with proto_dist=inet_tls in docker
run: |
./scripts/test/start-two-nodes-in-docker.sh -P $EMQX_IMAGE_TAG $EMQX_IMAGE_OLD_VERSION_TAG
HTTP_PORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "18083/tcp") 0).HostPort}}' haproxy)
# versions before 5.0.22 have hidden fields included in the API spec
export EMQX_SMOKE_TEST_CHECK_HIDDEN_FIELDS='no'
./scripts/test/emqx-smoke-test.sh localhost $HTTP_PORT
# cleanup
./scripts/test/start-two-nodes-in-docker.sh -c

View File

@ -31,8 +31,9 @@
%% TODO: move to emqx_dashboard when we stop building api schema at build time
-export([
hotconf_schema_json/1,
bridge_schema_json/1
hotconf_schema_json/0,
bridge_schema_json/0,
hocon_schema_to_spec/2
]).
%% for rpc
@ -149,7 +150,6 @@ dump_schema(Dir, SchemaModule) ->
lists:foreach(
fun(Lang) ->
ok = gen_config_md(Dir, SchemaModule, Lang),
ok = gen_api_schema_json(Dir, Lang),
ok = gen_schema_json(Dir, SchemaModule, Lang)
end,
["en", "zh"]
@ -176,41 +176,15 @@ gen_schema_json(Dir, SchemaModule, Lang) ->
IoData = emqx_utils_json:encode(JsonMap, [pretty, force_utf8]),
ok = file:write_file(SchemaJsonFile, IoData).
%% TODO: delete this function when we stop generating this JSON at build time.
gen_api_schema_json(Dir, Lang) ->
gen_api_schema_json_hotconf(Dir, Lang),
gen_api_schema_json_bridge(Dir, Lang).
%% TODO: delete this function when we stop generating this JSON at build time.
gen_api_schema_json_hotconf(Dir, Lang) ->
File = schema_filename(Dir, "hot-config-schema-", Lang),
IoData = hotconf_schema_json(Lang),
ok = write_api_schema_json_file(File, IoData).
%% TODO: delete this function when we stop generating this JSON at build time.
gen_api_schema_json_bridge(Dir, Lang) ->
File = schema_filename(Dir, "bridge-api-", Lang),
IoData = bridge_schema_json(Lang),
ok = write_api_schema_json_file(File, IoData).
%% TODO: delete this function when we stop generating this JSON at build time.
write_api_schema_json_file(File, IoData) ->
io:format(user, "===< Generating: ~s~n", [File]),
file:write_file(File, IoData).
%% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time.
hotconf_schema_json(Lang) ->
hotconf_schema_json() ->
SchemaInfo = #{title => <<"EMQX Hot Conf API Schema">>, version => <<"0.1.0">>},
gen_api_schema_json_iodata(emqx_mgmt_api_configs, SchemaInfo, Lang).
gen_api_schema_json_iodata(emqx_mgmt_api_configs, SchemaInfo).
%% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time.
bridge_schema_json(Lang) ->
bridge_schema_json() ->
SchemaInfo = #{title => <<"EMQX Data Bridge API Schema">>, version => <<"0.1.0">>},
gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo, Lang).
schema_filename(Dir, Prefix, Lang) ->
Filename = Prefix ++ Lang ++ ".json",
filename:join([Dir, Filename]).
gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo).
%% TODO: remove it and also remove hocon_md.erl and friends.
%% markdown generation from schema is a failure and we are moving to an interactive
@ -270,50 +244,11 @@ gen_example(File, SchemaModule) ->
Example = hocon_schema_example:gen(SchemaModule, Opts),
file:write_file(File, Example).
%% TODO: move this to emqx_dashboard when we stop generating
%% this JSON at build time.
gen_api_schema_json_iodata(SchemaMod, SchemaInfo, Lang) ->
{ApiSpec0, Components0} = emqx_dashboard_swagger:spec(
gen_api_schema_json_iodata(SchemaMod, SchemaInfo) ->
emqx_dashboard_swagger:gen_api_schema_json_iodata(
SchemaMod,
#{
schema_converter => fun hocon_schema_to_spec/2,
i18n_lang => Lang
}
),
ApiSpec = lists:foldl(
fun({Path, Spec, _, _}, Acc) ->
NewSpec = maps:fold(
fun(Method, #{responses := Responses}, SubAcc) ->
case Responses of
#{
<<"200">> :=
#{
<<"content">> := #{
<<"application/json">> := #{<<"schema">> := Schema}
}
}
} ->
SubAcc#{Method => Schema};
_ ->
SubAcc
end
end,
#{},
Spec
),
Acc#{list_to_atom(Path) => NewSpec}
end,
#{},
ApiSpec0
),
Components = lists:foldl(fun(M, Acc) -> maps:merge(M, Acc) end, #{}, Components0),
emqx_utils_json:encode(
#{
info => SchemaInfo,
paths => ApiSpec,
components => #{schemas => Components}
},
[pretty, force_utf8]
SchemaInfo,
fun ?MODULE:hocon_schema_to_spec/2
).
-define(TO_REF(_N_, _F_), iolist_to_binary([to_bin(_N_), ".", to_bin(_F_)])).

View File

@ -45,18 +45,11 @@ schema("/schemas/:name") ->
'operationId' => get_schema,
get => #{
parameters => [
{name, hoconsc:mk(hoconsc:enum([hotconf, bridges]), #{in => path})},
{lang,
hoconsc:mk(typerefl:string(), #{
in => query,
default => <<"en">>,
desc => <<"The language of the schema.">>
})}
{name, hoconsc:mk(hoconsc:enum([hotconf, bridges]), #{in => path})}
],
desc => <<
"Get the schema JSON of the specified name. "
"NOTE: you should never need to make use of this API "
"unless you are building a multi-lang dashboaard."
"NOTE: only intended for EMQX Dashboard."
>>,
tags => ?TAGS,
security => [],
@ -71,14 +64,13 @@ schema("/schemas/:name") ->
%%--------------------------------------------------------------------
get_schema(get, #{
bindings := #{name := Name},
query_string := #{<<"lang">> := Lang}
bindings := #{name := Name}
}) ->
{200, gen_schema(Name, iolist_to_binary(Lang))};
{200, gen_schema(Name)};
get_schema(get, _) ->
{400, ?BAD_REQUEST, <<"unknown">>}.
gen_schema(hotconf, Lang) ->
emqx_conf:hotconf_schema_json(Lang);
gen_schema(bridges, Lang) ->
emqx_conf:bridge_schema_json(Lang).
gen_schema(hotconf) ->
emqx_conf:hotconf_schema_json();
gen_schema(bridges) ->
emqx_conf:bridge_schema_json().

View File

@ -26,7 +26,11 @@
-export([error_codes/1, error_codes/2]).
-export([file_schema/1]).
-export([filter_check_request/2, filter_check_request_and_translate_body/2]).
-export([
filter_check_request/2,
filter_check_request_and_translate_body/2,
gen_api_schema_json_iodata/3
]).
-ifdef(TEST).
-export([
@ -72,6 +76,8 @@
])
).
-define(SPECIAL_LANG_MSGID, <<"$msgid">>).
-define(MAX_ROW_LIMIT, 1000).
-define(DEFAULT_ROW, 100).
@ -192,6 +198,50 @@ file_schema(FileName) ->
}
}.
gen_api_schema_json_iodata(SchemaMod, SchemaInfo, Converter) ->
{ApiSpec0, Components0} = emqx_dashboard_swagger:spec(
SchemaMod,
#{
schema_converter => Converter,
i18n_lang => ?SPECIAL_LANG_MSGID
}
),
ApiSpec = lists:foldl(
fun({Path, Spec, _, _}, Acc) ->
NewSpec = maps:fold(
fun(Method, #{responses := Responses}, SubAcc) ->
case Responses of
#{
<<"200">> :=
#{
<<"content">> := #{
<<"application/json">> := #{<<"schema">> := Schema}
}
}
} ->
SubAcc#{Method => Schema};
_ ->
SubAcc
end
end,
#{},
Spec
),
Acc#{list_to_atom(Path) => NewSpec}
end,
#{},
ApiSpec0
),
Components = lists:foldl(fun(M, Acc) -> maps:merge(M, Acc) end, #{}, Components0),
emqx_utils_json:encode(
#{
info => SchemaInfo,
paths => ApiSpec,
components => #{schemas => Components}
},
[pretty, force_utf8]
).
%%------------------------------------------------------------------------------
%% Private functions
%%------------------------------------------------------------------------------
@ -482,6 +532,14 @@ maybe_add_summary_from_label(Spec, Hocon, Options) ->
get_i18n(Tag, ?DESC(Namespace, Id), Default, Options) ->
Lang = get_lang(Options),
case Lang of
?SPECIAL_LANG_MSGID ->
make_msgid(Namespace, Id, Tag);
_ ->
get_i18n_text(Lang, Namespace, Id, Tag, Default)
end.
get_i18n_text(Lang, Namespace, Id, Tag, Default) ->
case emqx_dashboard_desc_cache:lookup(Lang, Namespace, Id, Tag) of
undefined ->
Default;
@ -489,6 +547,14 @@ get_i18n(Tag, ?DESC(Namespace, Id), Default, Options) ->
Text
end.
%% Format$msgid:Namespace.Id.Tag
%% e.g. $msgid:emqx_schema.key.desc
%% $msgid:emqx_schema.key.label
%% if needed, the consumer of this schema JSON can use this msgid to
%% resolve the text in the i18n database.
make_msgid(Namespace, Id, Tag) ->
iolist_to_binary(["$msgid:", to_bin(Namespace), ".", to_bin(Id), ".", Tag]).
%% So far i18n_lang in options is only used at build time.
%% At runtime, it's still the global config which controls the language.
get_lang(#{i18n_lang := Lang}) -> Lang;

View File

@ -0,0 +1,52 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_dashboard_schema_api_SUITE).
-compile(nowarn_export_all).
-compile(export_all).
-include_lib("emqx/include/http_api.hrl").
-include_lib("eunit/include/eunit.hrl").
-define(SERVER, "http://127.0.0.1:18083/api/v5").
-import(emqx_mgmt_api_test_util, [request/2]).
all() ->
emqx_common_test_helpers:all(?MODULE).
init_per_suite(Config) ->
emqx_mgmt_api_test_util:init_suite([emqx_conf]),
Config.
end_per_suite(_Config) ->
emqx_mgmt_api_test_util:end_suite([emqx_conf]).
t_hotconf(_) ->
Url = ?SERVER ++ "/schemas/hotconf",
{ok, 200, Body} = request(get, Url),
%% assert it's a valid json
_ = emqx_utils_json:decode(Body),
ok.
t_bridges(_) ->
Url = ?SERVER ++ "/schemas/bridges",
{ok, 200, Body} = request(get, Url),
%% assert it's a valid json
_ = emqx_utils_json:decode(Body),
ok.

View File

@ -45,6 +45,17 @@ schema("/status") ->
#{
'operationId' => get_status,
get => #{
parameters => [
{format,
hoconsc:mk(
string(),
#{
in => query,
default => <<"text">>,
desc => ?DESC(get_status_api_format)
}
)}
],
description => ?DESC(get_status_api),
tags => ?TAGS,
security => [],
@ -70,7 +81,16 @@ path() ->
"/status".
init(Req0, State) ->
{Code, Headers, Body} = running_status(),
Format =
try
QS = cowboy_req:parse_qs(Req0),
{_, F} = lists:keyfind(<<"format">>, 1, QS),
F
catch
_:_ ->
<<"text">>
end,
{Code, Headers, Body} = running_status(Format),
Req = cowboy_req:reply(Code, Headers, Body, Req0),
{ok, Req, State}.
@ -78,29 +98,52 @@ init(Req0, State) ->
%% API Handler funcs
%%--------------------------------------------------------------------
get_status(get, _Params) ->
running_status().
get_status(get, Params) ->
Format = maps:get(<<"format">>, maps:get(query_string, Params, #{}), <<"text">>),
running_status(iolist_to_binary(Format)).
running_status() ->
running_status(Format) ->
case emqx_dashboard_listener:is_ready(timer:seconds(20)) of
true ->
BrokerStatus = broker_status(),
AppStatus = application_status(),
Body = io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), BrokerStatus, AppStatus]),
Body = do_get_status(AppStatus, Format),
StatusCode =
case AppStatus of
running -> 200;
not_running -> 503
end,
ContentType =
case Format of
<<"json">> -> <<"applicatin/json">>;
_ -> <<"text/plain">>
end,
Headers = #{
<<"content-type">> => <<"text/plain">>,
<<"content-type">> => ContentType,
<<"retry-after">> => <<"15">>
},
{StatusCode, Headers, list_to_binary(Body)};
{StatusCode, Headers, iolist_to_binary(Body)};
false ->
{503, #{<<"retry-after">> => <<"15">>}, <<>>}
end.
do_get_status(AppStatus, <<"json">>) ->
BrokerStatus = broker_status(),
emqx_utils_json:encode(#{
node_name => atom_to_binary(node(), utf8),
rel_vsn => vsn(),
broker_status => atom_to_binary(BrokerStatus),
app_status => atom_to_binary(AppStatus)
});
do_get_status(AppStatus, _) ->
BrokerStatus = broker_status(),
io_lib:format("Node ~ts is ~ts~nemqx is ~ts", [node(), BrokerStatus, AppStatus]).
vsn() ->
iolist_to_binary([
emqx_release:edition_vsn_prefix(),
emqx_release:version()
]).
broker_status() ->
case emqx:is_running() of
true ->

View File

@ -38,7 +38,10 @@ all() ->
get_status_tests() ->
[
t_status_ok,
t_status_not_ok
t_status_not_ok,
t_status_text_format,
t_status_json_format,
t_status_bad_format_qs
].
groups() ->
@ -87,8 +90,10 @@ do_request(Opts) ->
headers := Headers,
body := Body0
} = Opts,
QS = maps:get(qs, Opts, ""),
URL = ?HOST ++ filename:join(Path0),
{ok, #{host := Host, port := Port, path := Path}} = emqx_http_lib:uri_parse(URL),
{ok, #{host := Host, port := Port, path := Path1}} = emqx_http_lib:uri_parse(URL),
Path = Path1 ++ QS,
%% we must not use `httpc' here, because it keeps retrying when it
%% receives a 503 with `retry-after' header, and there's no option
%% to stop that behavior...
@ -165,3 +170,73 @@ t_status_not_ok(Config) ->
Headers
),
ok.
t_status_text_format(Config) ->
Path = ?config(get_status_path, Config),
#{
body := Resp,
status_code := StatusCode
} = do_request(#{
method => get,
path => Path,
qs => "?format=text",
headers => [],
body => no_body
}),
?assertEqual(200, StatusCode),
?assertMatch(
{match, _},
re:run(Resp, <<"emqx is running$">>)
),
ok.
t_status_json_format(Config) ->
Path = ?config(get_status_path, Config),
#{
body := Resp,
status_code := StatusCode
} = do_request(#{
method => get,
path => Path,
qs => "?format=json",
headers => [],
body => no_body
}),
?assertEqual(200, StatusCode),
?assertMatch(
#{<<"app_status">> := <<"running">>},
emqx_utils_json:decode(Resp)
),
ok.
t_status_bad_format_qs(Config) ->
lists:foreach(
fun(QS) ->
test_status_bad_format_qs(QS, Config)
end,
[
"?a=b",
"?format=",
"?format=x"
]
).
%% when query-sting is invalid, fallback to text format
test_status_bad_format_qs(QS, Config) ->
Path = ?config(get_status_path, Config),
#{
body := Resp,
status_code := StatusCode
} = do_request(#{
method => get,
path => Path,
qs => QS,
headers => [],
body => no_body
}),
?assertEqual(200, StatusCode),
?assertMatch(
{match, _},
re:run(Resp, <<"emqx is running$">>)
),
ok.

7
build
View File

@ -92,7 +92,7 @@ log() {
}
make_docs() {
local libs_dir1 libs_dir2 libs_dir3 docdir dashboard_www_static
local libs_dir1 libs_dir2 libs_dir3 docdir
libs_dir1="$("$FIND" "_build/$PROFILE/lib/" -maxdepth 2 -name ebin -type d)"
if [ -d "_build/default/lib/" ]; then
libs_dir2="$("$FIND" "_build/default/lib/" -maxdepth 2 -name ebin -type d)"
@ -113,14 +113,11 @@ make_docs() {
;;
esac
docdir="_build/docgen/$PROFILE"
dashboard_www_static='apps/emqx_dashboard/priv/www/static/'
mkdir -p "$docdir" "$dashboard_www_static"
mkdir -p "$docdir"
# shellcheck disable=SC2086
erl -noshell -pa $libs_dir1 $libs_dir2 $libs_dir3 -eval \
"ok = emqx_conf:dump_schema('$docdir', $SCHEMA_MODULE), \
halt(0)."
cp "$docdir"/bridge-api-*.json "$dashboard_www_static"
cp "$docdir"/hot-config-schema-*.json "$dashboard_www_static"
}
assert_no_compile_time_only_deps() {

View File

@ -1,21 +1,42 @@
emqx_mgmt_api_status {
get_status_api.desc:
"""Serves as a health check for the node. Returns a plain text response describing the status of the node. This endpoint requires no authentication.
"""Serves as a health check for the node.
Returns response to describe the status of the node and the application.
This endpoint requires no authentication.
Returns status code 200 if the EMQX application is up and running, 503 otherwise.
This API was introduced in v5.0.10.
The GET `/status` endpoint (without the `/api/...` prefix) is also an alias to this endpoint and works in the same way. This alias has been available since v5.0.0."""
The GET `/status` endpoint (without the `/api/...` prefix) is also an alias to this endpoint and works in the same way.
This alias has been available since v5.0.0.
Starting from v5.0.25 or e5.0.4, you can also use 'format' parameter to get JSON format information.
"""
get_status_api.label:
"""Service health check"""
get_status_response200.desc:
"""Node emqx@127.0.0.1 is started
"""If 'format' parameter is 'json', then it returns a JSON like below:<br/>
{
"rel_vsn": "v5.0.23",
"node_name": "emqx@127.0.0.1",
"broker_status": "started",
"app_status": "running"
}
<br/>
Otherwise it returns free text strings as below:<br/>
Node emqx@127.0.0.1 is started
emqx is running"""
get_status_response503.desc:
"""Node emqx@127.0.0.1 is stopped
emqx is not_running"""
"""When EMQX application is temporary not running or being restarted, it may return 'emqx is not_running'.
If the 'format' parameter is provided 'json', the nthe 'app_status' field in the JSON object is 'not_running'.
"""
get_status_api_format.desc:
"""Specify the response format, 'text' (default) to return the HTTP body in free text,
or 'json' to return the HTTP body with a JSON object."""
}

View File

@ -1,22 +1,34 @@
emqx_mgmt_api_status {
get_status_api.desc:
"""作为节点的健康检查。 返回一个纯文本的响应,描述节点状态。
"""节点的健康检查。 返回节点状态的描述信息
如果 EMQX 应用程序已经启动并运行,返回状态代码 200否则返回 503。
这个API是在v5.0.10中引入的。
GET `/status`端点(没有`/api/...`前缀)也是这个端点的一个别名,工作方式相同。 这个别名从v5.0.0开始就有了。"""
GET `/status`端点(没有`/api/...`前缀)也是这个端点的一个别名,工作方式相同。 这个别名从v5.0.0开始就有了。
自 v5.0.25 和 e5.0.4 开始,可以通过指定 'format' 参数来得到 JSON 格式的信息。"""
get_status_api.label:
"""服务健康检查"""
get_status_response200.desc:
"""Node emqx@127.0.0.1 is started
"""如果 'format' 参数为 'json'则返回如下JSON<br/>
{
"rel_vsn": "v5.0.23",
"node_name": "emqx@127.0.0.1",
"broker_status": "started",
"app_status": "running"
}
<br/>
否则返回2行自由格式的文本第一行描述节点的状态第二行描述 EMQX 应用运行状态。例如:<br/>
Node emqx@127.0.0.1 is started
emqx is running"""
get_status_response503.desc:
"""Node emqx@127.0.0.1 is stopped
emqx is not_running"""
"""如果 EMQX 应用暂时没有启动,或正在重启,则可能返回 'emqx is not_running'"""
get_status_api_format.desc:
"""指定返回的内容格式。使用 'text'(默认)则返回自由格式的字符串; 'json' 则返回 JSON 格式。"""
}

View File

@ -2,42 +2,89 @@
set -euo pipefail
[ $# -ne 2 ] && { echo "Usage: $0 ip port"; exit 1; }
[ $# -ne 2 ] && { echo "Usage: $0 host port"; exit 1; }
IP=$1
HOST=$1
PORT=$2
URL="http://$IP:$PORT/status"
BASE_URL="http://$HOST:$PORT"
## Check if EMQX is responding
ATTEMPTS=10
while ! curl "$URL" >/dev/null 2>&1; do
if [ $ATTEMPTS -eq 0 ]; then
echo "emqx is not responding on $URL"
wait_for_emqx() {
local attempts=10
local url="$BASE_URL"/status
while ! curl "$url" >/dev/null 2>&1; do
if [ $attempts -eq 0 ]; then
echo "emqx is not responding on $url"
exit 1
fi
sleep 5
ATTEMPTS=$((ATTEMPTS-1))
done
attempts=$((attempts-1))
done
}
## Get the JSON format status which is jq friendly and includes a version string
json_status() {
local url="${BASE_URL}/status?format=json"
local resp
resp="$(curl -s "$url")"
if (echo "$resp" | jq . >/dev/null 2>&1); then
echo "$resp"
else
echo 'NOT_JSON'
fi
}
## Check if the API docs are available
API_DOCS_URL="http://$IP:$PORT/api-docs/index.html"
API_DOCS_STATUS="$(curl -s -o /dev/null -w "%{http_code}" "$API_DOCS_URL")"
if [ "$API_DOCS_STATUS" != "200" ]; then
check_api_docs() {
local url="$BASE_URL/api-docs/index.html"
local status
status="$(curl -s -o /dev/null -w "%{http_code}" "$url")"
if [ "$status" != "200" ]; then
echo "emqx is not responding on $API_DOCS_URL"
exit 1
fi
fi
}
## Check if the swagger.json contains hidden fields
## fail if it does
SWAGGER_JSON_URL="http://$IP:$PORT/api-docs/swagger.json"
## assert swagger.json is valid json
JSON="$(curl -s "$SWAGGER_JSON_URL")"
echo "$JSON" | jq . >/dev/null
if [ "${EMQX_SMOKE_TEST_CHECK_HIDDEN_FIELDS:-yes}" = 'yes' ]; then
check_swagger_json() {
local url="$BASE_URL/api-docs/swagger.json"
## assert swagger.json is valid json
JSON="$(curl -s "$url")"
echo "$JSON" | jq . >/dev/null
## assert swagger.json does not contain trie_compaction (which is a hidden field)
if echo "$JSON" | grep -q trie_compaction; then
echo "swagger.json contains hidden fields"
exit 1
fi
fi
}
check_schema_json() {
local name="$1"
local expected_title="$2"
local url="$BASE_URL/api/v5/schemas/$name"
local json
json="$(curl -s "$url" | jq .)"
title="$(echo "$json" | jq -r '.info.title')"
if [[ "$title" != "$expected_title" ]]; then
echo "unexpected value from GET $url"
echo "expected: $expected_title"
echo "got : $title"
exit 1
fi
}
main() {
wait_for_emqx
local JSON_STATUS
JSON_STATUS="$(json_status)"
check_api_docs
## The json status feature was added after hotconf and bridges schema API
if [ "$JSON_STATUS" != 'NOT_JSON' ]; then
check_swagger_json
check_schema_json hotconf "EMQX Hot Conf API Schema"
check_schema_json bridges "EMQX Data Bridge API Schema"
fi
}
main