khrt / Raisin

Raisin - a REST API micro framework for Perl 🐫 🐪
61 stars 30 forks source link

Coercion of Type::Tiny types #32

Closed djzort closed 5 years ago

djzort commented 7 years ago

Is there a way to trigger Type::Tiny to coerce the values?

Potentially like

    params( requires('postcode', type => PostCode, desc => 'Post Code', **coerce => 1** ),
            requires('prodcode', type => ProdCode, desc => 'Product Code'),
            optional('orderdate',type => Str,      desc => 'Order Date', default => 'now')
    );

Sort of like how you might go

has lines => ( is => "ro", isa => ArrayRef->plus_coercions(LinesFromStr), coerce => 1, );

See also http://search.cpan.org/~tobyink/Type-Tiny-1.000006/lib/Type/Tiny/Manual/Coercions.pod

khrt commented 7 years ago

At the moment coercions do not work with Raisin. I'm going to implement them soon together with two other issues.

djzort commented 7 years ago

Cool. Thanks for quick reply

mschout commented 6 years ago

+1

slobo commented 5 years ago

+1

khrt commented 5 years ago

Could you guys take a look at #54 if it's something you would expect from the feature.

mschout commented 5 years ago

I think we need to re-open this. What ended up in master has an eval inside of another eval in Raisin::Param::validate where it runs the coercion. So if the coercion fails, the exception should not be swallowed up here. Raisin doesn't treat this as a "invalid parameters" request as a result.

This means that either I have to check if the type is valid again inside the controller, which makes the coercion kind of pointless. I expect to get a "Invalid parameters"' response if there is no coercion that satisfies the type constraint. I can submit a PR if you like, but the fix is to remove the eval. You could keep the eval and warn, and then re-throw the exception I suppose if you want to keep the warning about the coercion failing as well. Here is what the eval block inside of validate looks like in the working version for me.

Disclaimer: I didn't test this with Types::Standard. We use Moose types exclusively :).

    eval {
        if ($self->type->has_coercion && $self->coerce) {
            $$ref_value = $self->type->coerce($$ref_value);
        }

        if ($self->type->isa('Moose::Meta::TypeConstraint')) {
            $self->type->assert_valid($$ref_value);
        }
        else {
            $$ref_value = $self->type->($$ref_value);
        }
    };
    if (my $e = $@) {
        unless ($quiet) {
            Raisin::log(warn => 'Param `%s` didn\'t pass constraint `%s` with value "%s"',
                $self->name, $self->type->name, $$ref_value);
        }
        return;
    }