Packages

jesse (JSon Schema Erlang) is an implementation of a JSON Schema validator for Erlang.

Current section

Files

Jump to
shiguredo_jesse src jesse_error.erl
Raw

src/jesse_error.erl

%%%=============================================================================
%% Copyright 2012- Klarna AB
%% Copyright 2015- AUTHORS
%% Copyright 2023- Shiguredo Inc.
%%
%% 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.
%%
%% @doc Json schema validation module.
%%
%% This module is the core of jesse, it implements the validation functionality
%% according to the standard.
%% @end
%%%=============================================================================
-module(jesse_error).
-export([default_error_handler/3,
handle_data_invalid/3,
handle_schema_invalid/2,
to_json/1, to_json/2,
reason_to_jsone/1]).
-export_type([error/0,
error_reason/0]).
-type error() :: {error, [error_reason()]}.
-type error_reason() :: {schema_invalid,
Schema :: jesse:json_term(),
Error :: error_type()} |
{data_invalid,
Schema :: jesse:json_term(),
Error :: error_type(),
Data :: jesse:json_term(),
Path :: [binary()]} |
{data_error,
{parse_error, _}} |
{schema_error,
{parse_error, _}}.
-type error_type() :: atom() |
{atom(), jesse:json_term()} |
{atom(), binary()} |
{atom(), [error_reason()]}.
%% Includes
-include("jesse_schema_validator.hrl").
%% @doc Implements the default error handler.
%% If the length of `ErrorList' exceeds `AllowedErrors' then the function
%% throws an exception, otherwise adds a new element to the list and returns it.
-spec default_error_handler(Error :: error_reason(),
ErrorList :: [error_reason()],
AllowedErrors :: jesse:allowed_errors()) -> [error_reason()] | no_return().
default_error_handler(Error, ErrorList0, AllowedErrors) ->
ErrorList = ErrorList0 ++ [Error],
case AllowedErrors > length(ErrorList0) orelse AllowedErrors =:= ?INFINITY of
true ->
ErrorList;
false ->
throw(ErrorList)
end.
%% @doc Generates a new data error and returns the updated state.
-spec handle_data_invalid(Info :: error_type(),
Value :: jesse:json_term(),
State :: jesse_state:state()) -> jesse_state:state().
handle_data_invalid(Info, Value, State) ->
Error = {?data_invalid,
jesse_state:get_current_schema(State),
Info,
Value,
lists:reverse(jesse_state:get_current_path(State))},
handle_error(Error, State).
%% @doc Generates a new schema error and returns the updated state.
-spec handle_schema_invalid(Info :: schema_invalid | error_type(),
State :: jesse_state:state()) -> jesse_state:state().
handle_schema_invalid(Info, State) ->
Error = {?schema_invalid,
jesse_state:get_current_schema(State),
Info},
handle_error(Error, State).
-spec to_json(Error :: error()) -> binary().
to_json(Error) ->
to_json(Error, [{indent, 2}, {space, 1}]).
-spec to_json(Error :: error(), JsoneOptions :: [jsone:encode_option()]) -> binary().
to_json({error, Reasons}, JsoneOptions) ->
JsxReasons = lists:map(fun reason_to_jsone/1, Reasons),
jsone:encode([{reasons, JsxReasons}], JsoneOptions).
-spec reason_to_jsone(Reason :: error_reason()) -> jesse:json_term().
reason_to_jsone({?schema_invalid, Schema, {Error, ErrorDetails}}) ->
[{invalid, schema},
{schema, Schema},
{error, Error},
{error_details, ErrorDetails}];
reason_to_jsone({?schema_invalid, Schema, Error}) ->
[{invalid, schema},
{schema, Schema},
{error, Error}];
reason_to_jsone({?data_invalid, Schema, {Error, ErrorDetails}, Data, Path}) ->
[{invalid, data},
{schema, Schema},
{error, Error},
{error_details, ErrorDetails},
{data, Data},
{path, Path}];
reason_to_jsone({?data_invalid, Schema, Error, Data, Path}) ->
[{invalid, data},
{schema, Schema},
{error, Error},
{data, Data},
{path, Path}].
%%% Internal functions
%% @private
handle_error(Error, State) ->
ErrorHandler = jesse_state:get_error_handler(State),
ErrorList = jesse_state:get_error_list(State),
AllowedErrors = jesse_state:get_allowed_errors(State),
NewErrorList = ErrorHandler(Error, ErrorList, AllowedErrors),
jesse_state:set_error_list(State, NewErrorList).