Seems like you understand your problem and have a well-thought out design
pattern!  I think what you are wanting to accomplish elegantly is exactly
what Mojolicious was built for
<https://mojolicious.org/perldoc/Mojolicious/Guides/Routing#BASICS>!

Your two sample routes can be condensed into one to handle any number of
customers, subclassed from a base class:

  $r->get('/api/v1/:controller/box/:id')->to('#open_box');

$ mojo generate app
   :
$ cat my_app/lib/MyApp.pm my_app/lib/MyApp/Controller/Customer.pm
my_app/lib/MyApp/Controller/Kwikemart.pm
my_app/lib/MyApp/Controller/Ezymart.pm
package MyApp;
use Mojo::Base 'Mojolicious';
sub startup {
  my $self = shift;
  my $r = $self->routes;
  $r->get('/api/v1/:controller/box/:id')->to('#open_box');
}
1;
package MyApp::Controller::Customer;
use Mojo::Base 'Mojolicious::Controller';
sub open_box { die "open_box method not implemented by subclass" }
1;
package MyApp::Controller::Kwikemart;
use Mojo::Base 'MyApp::Controller::Customer';
sub open_box {
  my $self = shift;
  $self->render(text => 'Hello, Kwikemart Customer!');
}
1;
package MyApp::Controller::Ezymart;
use Mojo::Base 'MyApp::Controller::Customer';
sub open_box {
  my $self = shift;
  $self->render(text => 'Welcome to Ezymart!');
}
1;
$ perl my_app/script/my_app routes
/api/v1/:controller/box/:id  GET  apiv1controllerboxid
*$ perl my_app/script/my_app get /api/v1/kwikemart/box/1*

*Hello, Kwikemart Customer!*
*$ perl my_app/script/my_app get /api/v1/ezymart/box/1*

*Welcome to Ezymart!*

On Wed, Jan 2, 2019 at 9:04 PM <hwmbo.l...@gmail.com> wrote:

> Hey, no problem. Mojolicious so far, can do just about anything I can
> think of, without much difficulty, as most stuff just work out of the box,
> which is a pleasant surprise.
>
> If you don't mind, I'll take a step back, and describe my design and
> reason behind it, and see if you can maybe spot something that's wrong with
> my approach. Here's the hypothetical scenario:
>
> 1. Two customers, one Kwikemart, and one Ezymart, they both handle boxes,
> but in different ways, one open it with a cutter, say, and the other one
> insist on using bare hands.
> 2. So I build one Customer class, and extend it, to implement actual
> customer. Both Kwikemart and Ezymart are children of Customer class, and
> each has a open_box() method, but within it, they each do their own thing.
> 3. In order to expose the boxes' content as RESTful resource, the url to
> access them, will be something like /api/v1/:customer/box/:boxid
>
> Of course, I could just code the route explicitly, since there's only two
> customer, by having:
>
>
>  $r->get('/api/v1/kwikemart/box/:id')->to('Customer::Kwikemart#open_box');
>      $r->get('/api/v1/ezymart/box/:id')->to('Customer::Ezymart#open_box');
>
> However, it just feels not elegant. The name of the class, is the only
> difference between the two different routes, and it'll be great to
> generalize it within the dispatching process, so if I have hundreds
> customers to do tomorrow, each of their own variants of 'open_box()'
> action, can be routed with just one call, instead of hundreds, as long as
> the url conforms to the '/api/v1/:customer/box/:id' format.
>
> Maybe I am just trying to be too clever for my own good, but I really
> think there must be an easy and elegant way to do this?
>
>
>
>
> On Wednesday, January 2, 2019 at 4:27:44 PM UTC-6, Stefan Adams wrote:
>>
>> Hi!  I'm glad you were able to figure that out and even using the more
>> advanced hook feature, but if I'm understanding your objective correctly, I
>> would advise that you follow the references I shared.  In essence, if I'm
>> reading it correctly, you are using a framework and then solving problems
>> on your own which are already solved by the framework.
>>
>> I just want to make sure you get off to a good start with Mojolicious so
>> that you can reap the full benefits of the framework and not become
>> irritated that it's not doing things that you want easily -- essentially
>> questioning why you're using this framework in the first place.  :)
>>
>> I'd recommend starting with a Mojolicious::Lite app.
>>
>> Start with the Hello World
>> <https://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial#Hello-World>
>> in the Tutorial.  And then expand it for your needs, perhaps like so:
>>
>> #!/usr/bin/env perluse Mojolicious::Lite;
>> get '/:customer' => sub {
>>   my $c = shift;
>>   $c->render(inline => 'Hello, <%= param "customer" %>!');};
>>
>> app->start;
>>
>>
>> Also, just to show some other equivalent ways to do the same thing:
>>
>> #!/usr/bin/env perluse Mojolicious::Lite;
>> get '/:customer' => sub {
>>   my $c = shift;  my $customer = $c->param('customer');
>>   $c->render(inline => 'Hello, <%= $customer %>!', customer => $customer);};
>>
>> app->start;
>>
>>
>> Also:
>>
>> #!/usr/bin/env perluse Mojolicious::Lite;
>> get '/:customer' => sub {
>>   my $c = shift;  $c->render(inline => 'Hello, <%= $c->param("customer") 
>> %>!');};
>>
>> app->start;
>>
>>
>> On Wed, Jan 2, 2019 at 3:39 PM <hwmbo...@gmail.com> wrote:
>>
>>> Thanks Stefan.
>>>
>>>
>>> So, trying a different tack, I was able to parse the url of a request
>>> with a 'before_depatch' hook, and figure out what Customer Class should be
>>> used, before routing happens.
>>>
>>> Assuming the request url is /kwikemart/liquor/22, I figure out the
>>> customer name (kwikemart) like this:
>>>
>>>
>>> sub startup {
>>>     my $self = shift;
>>>     $self->req->url->path =~ m#^/(\w+)/.+#;
>>>     $customer = $1;}
>>>
>>>
>>> The question is, where to store this $customer, so I can use it to
>>> specify the correct route later? I still don't quite get how Mojo::Base
>>> Class work. Not sure how to correctly create custom attribute, that's local
>>> to each request, so it can be used within a $r->to() call.
>>>
>>>
>>>
>>>
>>>
>>> On Wednesday, January 2, 2019 at 4:34:20 AM UTC-6, hwmbo...@gmail.com
>>> wrote:
>>>>
>>>> Hi. I want to route a request to a controller that's dynamically
>>>> constructed, base on a place holder in the url. To illustrate, I want do
>>>> something like the following:
>>>>
>>>> use Mojo::Base 'Mojolicious';
>>>>
>>>> sub startup {
>>>>
>>>> my $r = $self->routes;
>>>>
>>>>            my $route = $r->get('/:customer/boxs/:id');
>>>>
>>>>
>>>> [ somehow, extract the :customer holder into a variable $customer, then
>>>> ]
>>>>
>>>>            $route->(
>>>>
>>>> controller => "$customer::boxs',
>>>>
>>>> action     => 'get_list',
>>>>
>>>> );
>>>>
>>>> }
>>>>
>>>>
>>>> I tried but can't seem to find way to this, and I'm not sure if this is
>>>> possible?
>>>> Some pointer is appreciated. Thanks.
>>>>
>>>>
>>>>
>>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Mojolicious" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to mojolicious...@googlegroups.com.
>>> To post to this group, send email to mojol...@googlegroups.com.
>>> Visit this group at https://groups.google.com/group/mojolicious.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>> --
> You received this message because you are subscribed to the Google Groups
> "Mojolicious" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to mojolicious+unsubscr...@googlegroups.com.
> To post to this group, send email to mojolicious@googlegroups.com.
> Visit this group at https://groups.google.com/group/mojolicious.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to mojolicious+unsubscr...@googlegroups.com.
To post to this group, send email to mojolicious@googlegroups.com.
Visit this group at https://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/d/optout.

Reply via email to