Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Brannigan: hash validation

by henzen (Acolyte)
on Feb 14, 2018 at 11:30 UTC ( #1209129=perlquestion: print w/replies, xml ) Need Help??
henzen has asked for the wisdom of the Perl Monks concerning the following question:

Greetings all,

Hopefully someone has used the Brannigan module before.

Validating whether a hash key is present works fine. However, I need to check whether unknown/junk keys are being submitted.

For example:
use strict; use warnings; use Brannigan; use JSON; use Data::Dumper; my $json = q| { "method": "xxx", "backend": { "client": "mytest009", "pw": "sdkjfhsfjhKJH87" }, "blah": "123" # Junk }|; my $data = decode_json($json); my $b = Brannigan->new({ name => 'jsonPost', params => { method => { required => 1, one_of => ['xxx', ], }, backend => { hash => 1, keys => { client => { required => 1 }, pw => { required => 1 }, } }, } }); my $result = $b->process('jsonPost', $data); if ($result->{_rejects}) { print "ERROR\n"; print Dumper $result->{_rejects}, "\n"; } else { print "OK\n"; }

This code validates fine, but I need "blah" or any other unknown key to fail the validation.

Any ideas?


Replies are listed 'Best First'.
Re: Brannigan: hash validation
by AnomalousMonk (Chancellor) on Feb 14, 2018 at 12:51 UTC

    How about something like:

    c:\@Work\Perl\monks\henzen>perl -wMstrict -MData::Dump -le "use JSON; ;; my $json = q{ { \"method\": \"xxx\", \"backend\": { \"client\": \"mytest009\", \"pw\": \"sdkjfhsfjhKJH87\" }, \"blah\": \"123\" }}; my $data = decode_json($json); dd $data; ;; my %valid = map { $_ => 1 } qw(method backend); my @invalid = grep { ! exists $valid{$_} } keys %$data; die qq{invalid keys(s) present: @invalid} if @invalid; " { backend => { client => "mytest009", pw => "sdkjfhsfjhKJH87" }, blah => 123, method => "xxx", } invalid keys(s) present: blah at -e line 1.
    Of course, you have to know all the valid keys in advance, and it's only a top-level check, but maybe a starting point.

    Give a man a fish:  <%-{-{-{-<

Re: Brannigan: hash validation
by 1nickt (Monsignor) on Feb 14, 2018 at 13:28 UTC

    Hi, I have never heard of that module (<RANT>And I think modules should have sensible, descriptive names!</RANT>).

    I tried using JSON::Validator but it doesn't seem to support "additionalProperties": "false" even with its latest version (also it requires installing the entire Mojolicious application, which I think is silly). JSON::Schema is even less up to date with newer JSON Schema versions, unfortunately, so I didn't try with that.

    However, you can easily create a Type that will do what you want, using another of tobyink's creations, Type::Tiny:

    use strict; use warnings; package MyTypes { use parent 'Type::Library'; use Type::Utils; use Types::Standard qw/ Dict Enum Str /; declare MyType => as Dict[ method => Enum['xxx'], backend => Dict[ client => Str, pw => Str, ], ]; }; package main { use JSON; MyTypes->import(qw/ +MyType /); my $data = from_json q|{ "method": "xxx", "backend": { "client": "mytest009", "pw": "sdkjfhsfjhKJH87" }, "blah": "123" }|; assert_MyType( $data ); }; __END__
    Reference {"backend" => {"client" => "mytest009","pw" => "sdkjfhsfjhKJ +...} did not pass type constraint "MyType" at line 31 "MyType" is a subtype of "Dict[backend=>Dict[client=>Str,pw=>Str], +method=>Enum["xxx"]]" Reference {"backend" => {"client" => "mytest009","pw" => "sdkjfhsf +jhKJ...} did not pass type constraint "Dict[backend=>Dict[client=>Str +,pw=>Str],method=>Enum["xxx"]]" "Dict[backend=>Dict[client=>Str,pw=>Str],method=>Enum["xxx"]]" doe +s not allow key "blah" to appear in hash

    Hope this helps!

    The way forward always starts with a minimal test.
      hmm thanks, lemme have a gander at this goodie...
        Thanks 1nickt,

        This looks like it will work - I've been able to figure out most from the docs (I really wish module creators would have real-life examples, but anyway).

        Is there a way to do an array count validation?:
        use strict; use warnings; package JSONTypes { use parent 'Type::Library'; use Type::Utils; use Types::Standard qw/ Dict Enum Str Tuple ArrayRef Optional Rege +xpRef Int /; declare JSONType => as Dict[ method => Enum[qw(xxx yyy)], backend => Dict[ num => Int, other => Optional[Str], StrMatch[qr/^[a-z0-9]+$/] ], # following works, but how to check that the array has at least + (say) 2 elements - {2,} clientArr => ArrayRef[ Dict[ num => Int, ], ] ]; }; package main { use JSON; JSONTypes->import(qw/ +JSONType /); my $data = from_json q|{ "method": "xxx", "backend": { "num": 1, "client": "mytest009b" }, "clientArr": [{ "num": "1" }, { "num": "2" }] }|; my $ret = eval { assert_JSONType( $data ); }; if ($@) { print "ERROR\n$@\n"; } else { print "OK\n"; } };

        I'd appreciate any pointers.


        Edit: Figured out regex - use StrMatch[]
        Edit 2: Validating array count can be done with an anon sub, but it then kills the other check:
        clientArr => ArrayRef[ Dict[ num => Int, ], ], clientArr => sub { if (scalar @$_ < 2) { print "ERROR: clientArr too small\n"; exit 1; } else { } return 1; }

        So I guess the question is how to combine those two checks (without having to hand code the num=>Int checks in pure Perl of course).
Re: Brannigan: hash validation
by Anonymous Monk on Feb 14, 2018 at 14:23 UTC
    I tried and finally gave up on Brannigan. Wonderful idea, sort of like what happens when YACC meets XSLT. But it is so generalized that I could never get it to a point where I was confident that it was doing what I wanted. It seems better suited for checking what data is, but not so much for detecting when extraneous data exists (which seems to be your use-case). I cut my losses and did it the hard way.

      Please consider posting with a named account—or technical details on the hard way—so others can know how much credibility to attach to your opinion. As an AnonyMonk it's not worth the electricity that lights the pixels to display it since we have no idea if your opinion is solid gold or gobshite vomitus #FakeNews. Acronym dropping and being excited about XSLT points the compass toward the latter pole in my book.

        ? solid gold or #FakeNews

        Ha! That sounds like you've lost access to the central git repository where #RealTruth is kept.

        RTFM? If the pod matches the opinion ( extras undetected ) you can believe it ... or just believe the pod?

        Crusading against AM am YOING

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1209129]
Approved by hippo
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (3)
As of 2018-08-17 05:44 GMT
Find Nodes?
    Voting Booth?
    Asked to put a square peg in a round hole, I would:

    Results (174 votes). Check out past polls.