Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
{erl_opts, [debug_info]}.
{deps, [
{nova, {git, "[email protected]:novaframework/nova.git", {tag, "v0.13.0"}}},
{jesse, "1.8.1"}
]}.

{dialyzer, [
{plt_extra_apps, [
nova,
cowboy,
ranch
]}
]}.

{project_plugins, [
{erlfmt, "~>1.3"}
]}.
Expand Down
31 changes: 28 additions & 3 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
{"1.2.0",
[{<<"jesse">>,{pkg,<<"jesse">>,<<"1.8.1">>},0}]}.
[{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.13.0">>},1},
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.16.0">>},2},
{<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},1},
{<<"jesse">>,{pkg,<<"jesse">>,<<"1.8.1">>},0},
{<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"5.4.0">>},1},
{<<"nova">>,
{git,"[email protected]:novaframework/nova.git",
{ref,"7b4e14e17e0a63b40dc64c4894eb68ae2fd48140"}},
0},
{<<"ranch">>,{pkg,<<"ranch">>,<<"2.2.0">>},2},
{<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.11">>},1},
{<<"thoas">>,{pkg,<<"thoas">>,<<"1.2.1">>},1}]}.
[
{pkg_hash,[
{<<"jesse">>, <<"C9E3670C7EE40F719734E3BC716578143AABA93FC7525A02A7D5CB300B3AD71E">>}]},
{<<"cowboy">>, <<"09D770DD5F6A22CC60C071F432CD7CB87776164527F205C5A6B0F24FF6B38990">>},
{<<"cowlib">>, <<"54592074EBBBB92EE4746C8A8846E5605052F29309D3A873468D76CDF932076F">>},
{<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>},
{<<"jesse">>, <<"C9E3670C7EE40F719734E3BC716578143AABA93FC7525A02A7D5CB300B3AD71E">>},
{<<"jhn_stdlib">>, <<"FAC6F19B35351278F1CB156E23A5B2A6047A9DD5AB1FD9E1189A7918006DF7ED">>},
{<<"ranch">>, <<"25528F82BC8D7C6152C57666CA99EC716510FE0925CB188172F41CE93117B1B0">>},
{<<"routing_tree">>, <<"72ACEF2095F0EC804F7AFD07EF781DDE5009425A1CA0A28F0706B1DB334A4812">>},
{<<"thoas">>, <<"19A25F31177A17E74004D4840F66D791D4298C5738790FA2CC73731EB911F195">>}]},
{pkg_hash_ext,[
{<<"jesse">>, <<"0EDED3F18623FDA2F25989804A06CF518B4ACF2E9365B18C8E8C013D7E3C906F">>}]}
{<<"cowboy">>, <<"E724D3A70995025D654C1992C7B11DBFEA95205C047D86FF9BF1CDA92DDC5614">>},
{<<"cowlib">>, <<"7F478D80D66B747344F0EA7708C187645CFCC08B11AA424632F78E25BF05DB51">>},
{<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>},
{<<"jesse">>, <<"0EDED3F18623FDA2F25989804A06CF518B4ACF2E9365B18C8E8C013D7E3C906F">>},
{<<"jhn_stdlib">>, <<"7EABD1B01D2DEFF495BF7C5CA1DBA4D3FA0B84DC3AF03CA85F31D52EBB03C6FC">>},
{<<"ranch">>, <<"FA0B99A1780C80218A4197A59EA8D3BDAE32FBFF7E88527D7D8A4787EFF4F8E7">>},
{<<"routing_tree">>, <<"85982C7AC502892C5179CD2A591331003BACD2D2A71723640BA7D23F45408E6E">>},
{<<"thoas">>, <<"E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A">>}]}
].
2 changes: 1 addition & 1 deletion src/nova_json_schemas.app.src
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{application, nova_json_schemas, [
{description, "An OTP library"},
{vsn, "0.1.0"},
{vsn, "0.2.0"},
{registered, []},
{applications, [
kernel,
Expand Down
63 changes: 33 additions & 30 deletions src/nova_json_schemas.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

-export([
load_local_schemas/0,
pre_request/2,
post_request/2,
pre_request/4,
post_request/4,
plugin_info/0
]).

Expand Down Expand Up @@ -34,17 +34,21 @@ load_local_schemas() ->
%% Pre-request callback
%% @end
%%--------------------------------------------------------------------
-spec pre_request(Req :: cowboy_req:req(), Options :: map()) ->
{ok, Req0 :: cowboy_req:req()}
| {stop, Req0 :: cowboy_req:req()}
| {error, Reason :: term()}.
pre_request(Req = #{extra_state := #{json_schema := SchemaLocation}=Extra, json := JSON}, Options) ->
-spec pre_request(Req :: cowboy_req:req(), Env :: any(), Options :: map(), _) ->
{ok, Req0 :: cowboy_req:req(), _}
| {stop, Req0 :: cowboy_req:req(), _}.
pre_request(
Req = #{extra_state := #{json_schema := SchemaLocation} = Extra, json := JSON},
_Env,
Options,
PluginState
) ->
JesseOpts = maps:get(jesse_options, Extra, []),
%% JSON have already been parsed so we can just continue with the validation
case validate_json(SchemaLocation, JSON, JesseOpts) of
ok ->
?LOG_DEBUG("Schema validation on JSON body successful"),
{ok, Req};
{ok, Req, PluginState};
{error, Errors} ->
?LOG_DEBUG("Got validation-errors on JSON body. Errors: ~p", [Errors]),
case maps:get(render_errors, Options, false) of
Expand All @@ -56,55 +60,54 @@ pre_request(Req = #{extra_state := #{json_schema := SchemaLocation}=Extra, json
),
ErrorStruct = render_error(Errors),
ErrorJson = erlang:apply(JsonLib, encode, [ErrorStruct]),
Req1 = cowboy_req:set_resp_body(ErrorJson, Req0),
Req2 = cowboy_req:reply(400, Req1),
{stop, Req2};
Reply = {reply, 400, ErrorJson},
{stop, Reply, Req0, PluginState};
_ ->
?LOG_DEBUG(
"render_errors-option not set for plugin nova_json_schemas - returning plain 400-status to requester"
),
Req0 = cowboy_req:reply(400, Req),
{stop, Req0}
Reply = {reply, 400, <<>>},
{stop, Reply, Req, PluginState}
end
end;
pre_request(#{extra_state := #{json_schema := _SchemaLocation}}, _Options) ->
pre_request(#{extra_state := #{json_schema := _SchemaLocation}}, _Env, _Options, _PluginState) ->
%% The body have not been parsed. Log and error and stop
?LOG_ERROR(
"JSON Schema is set in 'extra_state' but body have not yet been parsed - rearrange your plugins so that JSON plugin is ran before this.."
),
{error, body_not_parsed};
pre_request(Req, _Options) ->
error(body_not_parsed);
pre_request(Req, _Env, _Options, PluginState) ->
%% 'json_schema' is not set or 'extra_state' is completly missing. Just continue.
?LOG_DEBUG("No schema is set for this route so will continue executing"),
{ok, Req}.
{ok, Req, PluginState}.

%%--------------------------------------------------------------------
%% @doc
%% Post-request callback
%% @end
%%--------------------------------------------------------------------
-spec post_request(Req :: cowboy_req:req(), Options :: map()) ->
{ok, Req0 :: cowboy_req:req()}
| {stop, Req0 :: cowboy_req:req()}
| {error, Reason :: term()}.
post_request(Req, _Options) ->
{ok, Req}.
-spec post_request(Req :: cowboy_req:req(), Env :: _, Options :: map(), PluginState :: _) ->
{ok, Req0 :: cowboy_req:req(), _}.
post_request(Req, _Env, _Options, PluginState) ->
{ok, Req, PluginState}.

%%--------------------------------------------------------------------
%% @doc
%% nova_plugin callback. Returns information about the plugin.
%% @end
%%--------------------------------------------------------------------
-spec plugin_info() ->
{Title :: binary(), Version :: binary(), Author :: binary(), Description :: binary(), [
{Key :: atom(), OptionDescription :: binary()}
]}.
plugin_info() ->
{<<"JSON schema plugin">>, <<"0.0.2">>, <<"Niclas Axelsson <[email protected]">>,
<<"Validating JSON with schemas">>, [
#{
title => <<"JSON schema plugin">>,
description => <<"Validating JSON with schemas">>,
version => <<"0.2.0">>,
authors => [<<"Niclas Axelsson <[email protected]">>],
url => <<"https://github.com/novaframework/nova_json_schemas">>,
options => [
{render_errors, <<"If this is set, validation-errors is returned to the requester">>}
%% Options is specified as {Key, Description}
]}.
]
}.

validate_json(SchemaLocation, Json, JesseOpts) ->
case jesse:validate(SchemaLocation, Json, JesseOpts) of
Expand Down