i've got a problem that i wasn't able to solve yet, and hope you can help :)
i have build a CataPLACK-Application with a web-interface. Now i am supposed to establish a JSON/REST/XML-Api, so i thought i could do something like this:
/ => root
/blog/ => ...
/news/ => ...
/api =>chainedTo(root) PathPart(api) Args(1) { set_view($arg) };
how do i loop back api to root (/), so i can redispatch the whole request with a different view without having to establish a lot of "fake routines" ?
i feel there must be a clean way ...
Have a look at the differences between $c->forward / $c->detach and $c->visit / $c->go in the manual. I think you'll find you can probably build a $c->go() construct from within your api method that achieves what you're after.
It's still a bit messy though, particularly if you have to de-reference the URI back to an action manually.
You can achieve the same effect with a lot less hassle by adding the 'api' path-part at the end rather than the beginning, so it just becomes an argument to the request that you can test for in your auto sub, and set whatever stash variables you need. Then you don't need to do any re-dispatching. Only you can decide whether such a URI scheme will be clean enough and appropriate for your application.
Related
I have a large Catalyst app and want to get a list of all endpoints it supports (bonus points if it can tell me if the request method). Is there some easy way to ask Catalyst to list them?
Catalyst does not know the full set of paths. The true dispatch paths are resolved dynamically, iterating through DispatchType classes until one responds favourably to a call of match.
The debug option does a one-time enumeration of all possibilities that your controllers allow. If you want to interfere with this, you have to look at Catalyst::Dispatcher::_display_action_tables
It's a tree-walking algorithm that iterates through each route it finds at '/' and follows each subsequent route that $controller->actions returns. It's not easy to read, but you could conceivably implement a version of _display_action_tables that doesn't just print to a table, but does something else instead. Then call it in the live application with $c as argument and see what happens!
Reading http://search.cpan.org/~ether/Catalyst-Manual-5.9009/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod I see $c->stash(template => 'hello.tt');.
There is a template, but where is the view? Why is the view not specified explicitly?
Also: How to call a view explicitly (not by the template name)?
This can be a little tricky because it is a combination of extremely flexible and plain DWIW. The .tt in the template name indicates that Template::Toolkit is the presumptive default. It's not necessary to use this View at all but it is used in most of the documentation.
You can render whatever is in your stash/$ctx by forwarding to a view: $c->forward($c->view("JSON")); for example, or you can decide for the rest of the request cycle like this $c->stash( current_view => "CSV" ). You have to have the view(s) installed and configured in your application, of course. You can also use views directly-
my $body = $c->view("Xslate")->render($c, "folder/email_template.tx", $params);
A tricky part becomes what your end method(s) will do.
The generally recommended default is Catalyst::Action::RenderView. It is smart (and flexible if you want to change its behavior). If you have set a redirect, for example, it won't render a page, it will just do the redirect. If you have already generated $c->response->body content it will also "just stop" and trust that what you've already done is what you wanted.
There is enough complexity in the flexibility that I really recommend just putting together a toy app run in the restarting dev server and trying out all the things you want to understand better. None of it is that hard in itself but it all adds up to confusion unless you break it down into digestible chunks.
I need to handle some HTTP URLs in a Perl program, but I have doubts how should the URI class help me.
Particularly, I'd like the to use the URI class for resolving relative URLs and getting their components. However, the problems are:
I need a function to work with both URI objects and URI strings as arguments (or ensure only one gets passed)
sub foo_string_or_url {
my $uri = URI->new(shift);
is that the right approach? I don't quite like it, because it stringifies the URI and creates new object unnecessarily.
Extract the components
my $host = $uri->host;
This is also problematic, because not all URIs have host, particularly, if someone passes garbage to the function, this will die().
Resolve a relative URL
my $new_url = URI::URL->new($uri, $base)->abs;
IIUC, without the ->abs, the result will still stringify to the relative URL (and will not work for HTTP::Requests), am I right? Also, is this guaranteed to return a URI?
How should I handle these problems? The possibilities are
Use ->isa('URI') and ->can("host") all the time
Seems error prone and ugly to me
Don't use URI class at all and parse URLs using regexes
I'd still rather use a library solution than debug my own
Wrap URI operations in try { ... } catch { ... }
see the first point
Is there a sane, fool-proof way of using the URI classes? Something simple I haven't thought of (in the list above)?
I think your question can be summarised: parameter validation is tedious, what do I do about it?
I don't like it, either. This is a matter of differing opinion among developers, other say coercions are better than sliced bread, especially when automatically done by Moose. I argue that allowing only one type of simplifies the program. Also, YAGNI applies in the vast majority of cases. Reject wrong types, employ a helper module such as Params::Validate/MooseX::Method::Signatures/MooseX::Declare in order to avoid the manual checks as shown in your code samples.
This is the desired behaviour. Exception handling mechanisms let you write custom code appropriate for each situation. If you think it's not aesthetically pleasing, remove it and mind the consequences of letting exceptions go unchecked.
use Try::Tiny;
my $host;
try {
$host = $uri->host;
} catch {
warn "Could not determine host for $uri. Message was: $_. Retry/abort/ignore?\n";
…
};
Yes and yes.
I have seen the examples of Net::OpenID::Consumer::Lite on CPAN but I was hoping to get a single script that uses POST method. If nobody has this than I will post my solution back here once I get it working.
This seems to be the only applicable test in the manifest and it doesn't seem too useful
http://cpansearch.perl.org/src/TOKUHIROM/Net-OpenID-Consumer-Lite-0.02/xt/001_mixi.t Apache2::AuthMixi also uses it a bit
This module simply delegates to LWP::UserAgent. I don't like it, it should subclass LWP::UserAgent instead of delegating. You can find the docs for LWP::UserAgent on cpan, and access the base copy through the hidden method _ua (though, by convention, the preceding underscore tells you it isn't supported and it is supposed to be kept secret)
my $csr = Net::OpenID::Consumer::Lite->new();
$csr->_ua->post(); # same as LWP::UserAgent::post()
It seems as if you're supposed to use only handle_server_response() which calls _check_authentication() which calls _get() which delegates to ->_ua->get().
check_authentication() wants an HashRef jump-table with 5 events for not_openid, setup_required, cancelled, verified, and error. In addition I believe it wants a bunch of key (openid.) prefixed stuff, and values.
Per the code, for a request to be sent $request->{'openid.mode'} must exist in the $request and be set (preferably to) check_authentication, and not set to 'cancel'. The openid.user_setup_url key must logically not be set or it will just call the respective callback. It must also have an op_endpoint.endpoint key set, which is where the request is destined to go.
This code isn't hard to read, I'd suggesting taking a look The author also seems to have a bunch of modules which is a good sign. I don't like jump-tables with data like that, it seems kind of weird from a UI perspective.
Sorry this is a pretty long question, but i want to have some disucssions here.
i am new to zend and try to avoid using modules as I think the view aspect of zend is pretty flexible and module will add extra directory and confusion. However i am wondering one thing. The app i am building is pretty big it actually has the modules concept in the app.
I know if using module, things can be more organised, where you can put modules in its own directory and have seperate view and controller etc.
however i decided to simulate module directory in the form of
--lang/module(in fact the controller)/controller(that's the action)/action(that's the child-action)/other-params/--
how we go about and do this kind of simulation
The initial idea i have is add another route to the application take the 4th param as the child-action. e.g
class some_controller extend extends Zend_Controller_Action{
public function someAction{
switch (child-action) {
case 'child-action1':
....... excute some action
break;
case 'child-action2':
....... excute some action
break;....
}
}
something like that. Does that make sense or if there's any other approach? and with this approach how we integrate Zend_ACL as how to add the 'fake child action' as a resource?
Thank you.
Perhaps you could set up your routes like so:
/:controller/:action/:child-action
See here for more info on setting up routes.
Then in your action methods:
$childAction = $this->getParam('child-action');
// convert $childAction to camelCase.
if(method_exists($this, $childAction))
{
// Check ACL
$this->$childAction();
}
Do not name child actions with the Action postfix as that would allow the actions to be called directly. You could maybe postfix them with something like 'fooChild' but not 'fooChildAction' as they would then map to 'foo-child'.
I think this is making it plenty more complicated then just working with the module directory structure...
Which once set-up, is not that complicated at all, it's just a logical separation of classes...
It would make more sense to add a route ;)
have :module/:controller/:action/ -> admin/posts/add
and :module/posts/add/:action -> admin/posts/add/concept that would link to PostsAddController::ConceptAction();
better than switch statement i guess ;) But you can use it to... case "sth": $this->_forward('my-action','my-controller');