Skip to content

Commit

Permalink
Make graphql_cowboy_handler use correct error format, Format error me…
Browse files Browse the repository at this point in the history
…ssages
  • Loading branch information
Premwoik committed Dec 15, 2021
1 parent 866f878 commit 385e621
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 18 deletions.
12 changes: 8 additions & 4 deletions big_tests/tests/graphql_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -148,27 +148,31 @@ invalid_json_body_error(Config) ->
Body = <<"">>,
{Status, Data} = execute(Ep, Body, undefined),
?assertEqual({<<"400">>,<<"Bad Request">>}, Status),
?assertMatch(#{<<"errors">> := [#{<<"message">> := <<"invalid_json_body">>}]}, Data).
assert_code(invalid_json_body, Data).

no_query_supplied_error(Config) ->
Ep = ?config(schema_endpoint, Config),
Body = #{},
{Status, Data} = execute(Ep, Body, undefined),
?assertEqual({<<"400">>,<<"Bad Request">>}, Status),
?assertMatch(#{<<"errors">> := [#{<<"message">> := <<"no_query_supplied">>}]}, Data).
assert_code(no_query_supplied, Data).

variables_invalid_json_error(Config) ->
Ep = ?config(schema_endpoint, Config),
Body = #{<<"query">> => <<"{ field }">>, <<"variables">> => <<"{1: 2}">>},
{Status, Data} = execute(Ep, Body, undefined),
?assertEqual({<<"400">>,<<"Bad Request">>}, Status),
?assertMatch(#{<<"errors">> := [#{<<"message">> := <<"variables_invalid_json">>}]}, Data).
assert_code(variables_invalid_json, Data).

%% Helpers

assert_code(Code, Data) ->
BinCode = atom_to_binary(Code),
?assertMatch(#{<<"errors">> := [#{<<"extensions">> := #{<<"code">> := BinCode}}]}, Data).

assert_no_permissions(Status, Data) ->
?assertEqual({<<"400">>,<<"Bad Request">>}, Status),
?assertMatch(#{<<"errors">> := [#{<<"message">> := <<"no_permissions">>}]}, Data).
?assertMatch(#{<<"errors">> := [#{<<"extensions">> := #{<<"code">> := <<"no_permissions">>}}]}, Data).

assert_access_granted(Status, Data) ->
?assertEqual({<<"200">>,<<"OK">>}, Status),
Expand Down
18 changes: 10 additions & 8 deletions src/mongoose_graphql/mongoose_graphql_cowboy_handler.erl
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ is_authorized(Req, State) ->
{true, Req, State2}
catch
exit:Err ->
Msg = #{phase => authorize, error_term => Err},
reply_error(400, Msg, Req, State)
reply_error(400, make_error(authorize, Err), Req, State)
end.

resource_exists(#{method := <<"GET">>} = Req, State) ->
Expand Down Expand Up @@ -113,7 +112,7 @@ auth_admin(_, State) ->
State#{authorized => true}.

run_request(#{document := undefined}, Req, State) ->
reply_error(400, no_query_supplied, Req, State);
reply_error(400, make_error(parse_request, no_query_supplied), Req, State);
run_request(#{} = ReqCtx, Req, #{schema_endpoint := EpName,
authorized := AuthStatus} = State) ->
Ep = mongoose_graphql:get_endpoint(binary_to_existing_atom(EpName)),
Expand All @@ -137,7 +136,7 @@ gather(Req) ->
gather(Req2, JSON, Bindings)
catch
_:_ ->
{error, invalid_json_body}
{error, make_error(parse_request, invalid_json_body)}
end.

gather(Req, Body, Params) ->
Expand All @@ -162,10 +161,10 @@ variables([#{<<"variables">> := Vars} | _]) ->
try jiffy:decode(Vars, [return_maps]) of
null -> {ok, #{}};
JSON when is_map(JSON) -> {ok, JSON};
_ -> {error, variables_invalid_json}
_ -> {error, make_error(parse_request, variables_invalid_json)}
catch
_:_ ->
{error, variables_invalid_json}
{error, make_error(parse_request, variables_invalid_json)}
end;
is_map(Vars) ->
{ok, Vars};
Expand All @@ -184,9 +183,12 @@ operation_name([_ | Next]) ->
operation_name([]) ->
undefined.

make_error(Phase, Term) ->
#{error_term => Term, phase => Phase}.

reply_error(Code, Msg, Req, State) ->
Errors = mongoose_graphql_errors:format_error(Msg),
Body = jiffy:encode(#{errors => Errors}),
Error = mongoose_graphql_errors:format_error(Msg),
Body = jiffy:encode(#{errors => [Error]}),
Req2 = cowboy_req:set_resp_body(Body, Req),
Reply = cowboy_req:reply(Code, Req2),
{stop, Reply, State}.
24 changes: 18 additions & 6 deletions src/mongoose_graphql/mongoose_graphql_errors.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,34 @@ format_errors(Errors) ->
[format_error(E) || E <- Errors].

format_error(#{phase := Phase, error_term := Term}) when Phase =:= authorize;
Phase =:= parse_request;
Phase =:= parse ->
#{extensions => #{code => err_code(Phase, Term)},
message => iolist_to_binary(err_msg(Phase, Term))};
format_error(#{error_term := _} = Err) ->
graphql:format_errors(#{}, [Err]);
format_error(Err) ->
#{extensions => #{code => uncathegorized_error},
message => iolist_to_binary(io_lib:format("~p", Err))}.
message => iolist_to_binary(io_lib:format("~p", [Err]))}.

%% Internal

err_code(authorize, _Term) ->
authorization_error;
err_code(parse, Term) ->
element(1, Term).
err_code(_, Term) ->
simplify(Term).

simplify(A) when is_atom(A) -> A;
simplify(B) when is_binary(B) -> B;
simplify(T) when is_tuple(T) -> element(1, T).

err_msg(parse, Result) ->
parse_err_msg(Result);
err_msg(parse_request, Result) ->
parse_request_err_mgs(Result);
err_msg(authorize, Result) ->
authorize_err_msg(Result).

authorize_err_msg({request_error, {header, <<"authorization">>}, _}) ->
"Malformed authorization header.Please consult the relevant specification.";
"Malformed authorization header. Please consult the relevant specification";
authorize_err_msg({no_permissions, Op}) ->
io_lib:format("Cannot execute query ~s without permissions", [Op]).

Expand All @@ -52,3 +57,10 @@ parse_err_msg({parser_error, {Line, graphql_parser, Msg}}) ->
parse_err_msg({scanner_error, {Line, graphql_scanner, Msg}}) ->
Formatted = lists:flatten(graphql_scanner:format_error(Msg)),
io_lib:format("Cannot scan line ~B because of ~s", [Line, Formatted]).

parse_request_err_mgs(no_query_supplied) ->
"The query was not provided in request body";
parse_request_err_mgs(invalid_json_body) ->
"The request json body is invalid";
parse_request_err_mgs(variables_invalid_json) ->
"The variables' json is invalid".

0 comments on commit 385e621

Please sign in to comment.