Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I insert some route-checking middleware in Cro?

Say I need to check some URI before I serve some result. I can do something like this:

sub type-routes {
    route {
        get -> Str $type where $type ∈ @food-types {
            my %ingredients-table = $rrr.calories-table;
            my @result =  %ingredients-table.keys.grep: {
                %ingredients-table{$_}{$type} };
            content 'application/json', @result;
        }
        get -> Str $type where $type ∉ @food-types {
            not-found;
        }
    }
}

Basically, different signature for existing and non-existing products in this case. However, that same URI is going to be used all across routes. It would be interesting to be able to check it before any route gets matched, so that when it arrives to the route block, we know that it's OK. That way it could also be reused across different routes.

I have checked before and before-match, and apparently you can do it, but you need to analyze the request object to get to that, there's no simple way of doing it.

Alternatively, would there be any way of defining a "fallback-route" so that if an URI is not found, not-found is returned?

like image 946
jjmerelo Avatar asked May 12 '20 16:05

jjmerelo


1 Answers

Before giving the middleware answer, my first resort in situations like this is usually a subset type:

sub type-routes {
    route {
        my constant @food-types = <burgers pizzas beer>;
        my subset Food of Str where { $^type ∈ @food-types }

        get -> Food $type {
            my %ingredients-table = $rrr.calories-table;
            my @result =  %ingredients-table.keys.grep: {
                %ingredients-table{$_}{$type} };
            content 'application/json', @result;
        }
    }
}

This way, Food can be used across as many routes as you wish. There's no need for a fallback route (either in this solution or that in the original question) to produce not-found, because the router automatically produces that when no route matches the path segments anyway.

If wanting to go the middleware way, however, then the easiest approach is to obtain the path-segments of the request and check against the appropriate part:

sub type-routes {
    route {
        my constant @food-types = <burgers pizzas beer>;
        before {
            not-found unless request.path-segments[0] ∈ @food-types;
        }

        get -> Str $type {
            content 'application/json', <123 456>;
        }
    }
}
like image 72
Jonathan Worthington Avatar answered Nov 12 '22 10:11

Jonathan Worthington