25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-24 16:23:40 +01:00

Add support for rich error reporting for API

This commit is contained in:
Mickael Remond 2016-07-30 13:08:30 +02:00
parent fb2603d3cd
commit 39640b67c7
No known key found for this signature in database
GPG Key ID: E6F6045D79965AA3
3 changed files with 31 additions and 19 deletions

View File

@ -380,13 +380,12 @@ register(User, Host, Password) ->
{atomic, ok} -> {atomic, ok} ->
{ok, io_lib:format("User ~s@~s successfully registered", [User, Host])}; {ok, io_lib:format("User ~s@~s successfully registered", [User, Host])};
{atomic, exists} -> {atomic, exists} ->
String = io_lib:format("User ~s@~s already registered at node ~p", Msg = io_lib:format("User ~s@~s already registered", [User, Host]),
[User, Host, node()]), {error, conflict, 10090, Msg};
{conflict, String};
{error, Reason} -> {error, Reason} ->
String = io_lib:format("Can't register user ~s@~s at node ~p: ~p", String = io_lib:format("Can't register user ~s@~s at node ~p: ~p",
[User, Host, node(), Reason]), [User, Host, node(), Reason]),
{cannot_register, String} {error, cannot_register, 10001, String}
end. end.
unregister(User, Host) -> unregister(User, Host) ->

View File

@ -212,7 +212,7 @@ process(["help" | Mode], Version) ->
end; end;
process(["--version", Arg | Args], _) -> process(["--version", Arg | Args], _) ->
Version = Version =
try try
list_to_integer(Arg) list_to_integer(Arg)
catch _:_ -> catch _:_ ->
@ -321,7 +321,7 @@ call_command([CmdString | Args], Auth, AccessCommands, Version) ->
{ArgsFormat, ResultFormat} -> {ArgsFormat, ResultFormat} ->
case (catch format_args(Args, ArgsFormat)) of case (catch format_args(Args, ArgsFormat)) of
ArgsFormatted when is_list(ArgsFormatted) -> ArgsFormatted when is_list(ArgsFormatted) ->
Result = ejabberd_commands:execute_command(AccessCommands, Result = ejabberd_commands:execute_command(AccessCommands,
Auth, Command, Auth, Command,
ArgsFormatted, ArgsFormatted,
Version), Version),
@ -374,6 +374,12 @@ format_arg2(Arg, Parse)->
format_result({error, ErrorAtom}, _) -> format_result({error, ErrorAtom}, _) ->
{io_lib:format("Error: ~p", [ErrorAtom]), make_status(error)}; {io_lib:format("Error: ~p", [ErrorAtom]), make_status(error)};
%% An error should always be allowed to return extended error to help with API.
%% Extended error is of the form:
%% {error, type :: atom(), code :: int(), Desc :: string()}
format_result({error, ErrorAtom, Code, _Msg}, _) ->
{io_lib:format("Error: ~p", [ErrorAtom]), make_status(Code)};
format_result(Atom, {_Name, atom}) -> format_result(Atom, {_Name, atom}) ->
io_lib:format("~p", [Atom]); io_lib:format("~p", [Atom]);
@ -433,6 +439,7 @@ format_result(404, {_Name, _}) ->
make_status(ok) -> ?STATUS_SUCCESS; make_status(ok) -> ?STATUS_SUCCESS;
make_status(true) -> ?STATUS_SUCCESS; make_status(true) -> ?STATUS_SUCCESS;
make_status(Code) when is_integer(Code) -> Code;
make_status(_Error) -> ?STATUS_ERROR. make_status(_Error) -> ?STATUS_ERROR.
get_list_commands(Version) -> get_list_commands(Version) ->

View File

@ -220,12 +220,8 @@ process([Call], #request{method = 'POST', data = Data, ip = {IP, _} = IPPort} =
log(Call, Args, IPPort), log(Call, Args, IPPort),
case check_permissions(Req, Call) of case check_permissions(Req, Call) of
{allowed, Cmd, Auth} -> {allowed, Cmd, Auth} ->
case handle(Cmd, Auth, Args, Version, IP) of Result = handle(Cmd, Auth, Args, Version, IP),
{Code, Result} -> json_format(Result);
json_response(Code, jiffy:encode(Result));
{HTMLCode, JSONErrorCode, Message} ->
json_error(HTMLCode, JSONErrorCode, Message)
end;
%% Warning: check_permission direcly formats 401 reply if not authorized %% Warning: check_permission direcly formats 401 reply if not authorized
ErrorResponse -> ErrorResponse ->
ErrorResponse ErrorResponse
@ -247,8 +243,8 @@ process([Call], #request{method = 'GET', q = Data, ip = IP} = Req) ->
log(Call, Args, IP), log(Call, Args, IP),
case check_permissions(Req, Call) of case check_permissions(Req, Call) of
{allowed, Cmd, Auth} -> {allowed, Cmd, Auth} ->
{Code, Result} = handle(Cmd, Auth, Args, Version, IP), Result = handle(Cmd, Auth, Args, Version, IP),
json_response(Code, jiffy:encode(Result)); json_format(Result);
%% Warning: check_permission direcly formats 401 reply if not authorized %% Warning: check_permission direcly formats 401 reply if not authorized
ErrorResponse -> ErrorResponse ->
ErrorResponse ErrorResponse
@ -302,7 +298,7 @@ handle(Call, Auth, Args, Version, IP) when is_atom(Call), is_list(Args) ->
[{Key, undefined}|Acc] [{Key, undefined}|Acc]
end, [], ArgsSpec), end, [], ArgsSpec),
try try
handle2(Call, Auth, match(Args2, Spec), Version, IP) handle2(Call, Auth, match(Args2, Spec), Version, IP)
catch throw:not_found -> catch throw:not_found ->
{404, <<"not_found">>}; {404, <<"not_found">>};
throw:{not_found, Why} when is_atom(Why) -> throw:{not_found, Why} when is_atom(Why) ->
@ -448,12 +444,12 @@ format_command_result(Cmd, Auth, Result, Version) ->
{200, 0}; {200, 0};
{{_, rescode}, _} -> {{_, rescode}, _} ->
{200, 1}; {200, 1};
{_, {error, ErrorAtom, Code, Msg}} ->
format_error_result(ErrorAtom, Code, Msg);
{{_, restuple}, {V, Text}} when V == true; V == ok -> {{_, restuple}, {V, Text}} when V == true; V == ok ->
{200, iolist_to_binary(Text)}; {200, iolist_to_binary(Text)};
{{_, restuple}, {V, Text}} when V == conflict -> {{_, restuple}, {ErrorAtom, Msg}} ->
{409, iolist_to_binary(Text)}; format_error_result(ErrorAtom, 0, Msg);
{{_, restuple}, {_, Text2}} ->
{500, iolist_to_binary(Text2)};
{{_, {list, _}}, _V} -> {{_, {list, _}}, _V} ->
{_, L} = format_result(Result, ResultFormat), {_, L} = format_result(Result, ResultFormat),
{200, L}; {200, L};
@ -499,6 +495,11 @@ format_result(Tuple, {Name, {tuple, Def}}) ->
format_result(404, {_Name, _}) -> format_result(404, {_Name, _}) ->
"not_found". "not_found".
format_error_result(conflict, Code, Msg) ->
{409, Code, iolist_to_binary(Msg)};
format_error_result(_ErrorAtom, Code, Msg) ->
{500, Code, iolist_to_binary(Msg)}.
unauthorized_response() -> unauthorized_response() ->
json_error(401, 10, <<"Oauth Token is invalid or expired.">>). json_error(401, 10, <<"Oauth Token is invalid or expired.">>).
@ -507,6 +508,11 @@ badrequest_response() ->
badrequest_response(Body) -> badrequest_response(Body) ->
json_response(400, jiffy:encode(Body)). json_response(400, jiffy:encode(Body)).
json_format({Code, Result}) ->
json_response(Code, jiffy:encode(Result));
json_format({HTMLCode, JSONErrorCode, Message}) ->
json_error(HTMLCode, JSONErrorCode, Message).
json_response(Code, Body) when is_integer(Code) -> json_response(Code, Body) when is_integer(Code) ->
{Code, ?HEADER(?CT_JSON), Body}. {Code, ?HEADER(?CT_JSON), Body}.