FAQ
Hi,

I need to generate an XML output (Content-type: application/xml), but this XML output is the XML content which is stored in an XML file. I don't need to dinamically generate this XML content.
I have searched in google but I don't find any catalyst view module for managing this case. I don't know if exists any module for generating XML output from a static file as, for example, Catalyst::View::XSLT module (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm) does. That is, generate an output from a static file, in this case, an XML output.

I am not finding much information about designing your own views in Catalyst, or at least, I don't see much flexibility. All examples I have found need to be generated, through the helper view, with TT template or any other templates.
Is it possible to create your own view, with no template, and for example, in my case, read the output from a static file and send this output to the client? (I don't know exactly how Views works in Catalyst, though I have already read Catalyst tutorial and cookbook)

Thanks in advanced,


David



-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100305/d9c45e61/attachment.htm

Search Discussions

  • Jay Shirley at Mar 5, 2010 at 3:45 pm

    On Fri, Mar 5, 2010 at 5:10 AM, David wrote:
    Hi,

    I need to generate an XML output (Content-type: application/xml), but this
    XML output is the XML content which is stored in an XML file. I don't need
    to dinamically generate this XML content.
    I have searched in google but I don't find any catalyst view module for
    managing this case. I don't know if exists any module for generating XML
    output from a static file as, for example, Catalyst::View::XSLT module
    (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm)
    does. That is, generate an output from a static file, in this case, an XML
    output.

    I am not finding much information about designing your own views in
    Catalyst, or at least, I don't see much flexibility. All examples I have
    found need to be generated, through the helper view, with TT template or any
    other templates.
    Is it possible to create your own view, with no template, and for example,
    in my case, read the output from a static file and send this output to the
    client? (I don't know exactly how Views works in Catalyst, though I have
    already read Catalyst tutorial and cookbook)

    Thanks in advanced,


    David

    Well, you could do your own view or just rely on
    Catalyst::Plugin::Static::Simple:

    http://search.cpan.org/~mstrout/Catalyst-Plugin-Static-Simple-0.29/lib/Catalyst/Plugin/Static/Simple.pm#serve_static_file_$file_path

    You could wrap this in a view:

    package MyApp::View::StaticFile;

    use parent 'Catalyst::View';

    sub process {
    my ( $self, $c ) = @_;
    $c->serve_static_file( $c->stash->{static_file} );
    }

    1;



    Then just do $c->forward( $c->view('StaticFile') ); after setting the stash key.

    -Jay
  • David at Mar 5, 2010 at 6:46 pm
    Thanks Jay.

    I thought of that solution too when I had a look at Catalyst::Plugin::Static::Simple. But in this case, my doubt was, and is, how should I create the view through the helper?
    Most of the examples for creating views are TT views, so they create it as 'script/hello_create.pl view my_TT_view TT'.
    David




    ________________________________
    De: J. Shirley <jshirley@gmail.com>
    Para: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Enviado: vie,5 marzo, 2010 16:45
    Asunto: Re: [Catalyst] Best practices: XML output from static XML
    On Fri, Mar 5, 2010 at 5:10 AM, David wrote:
    Hi,

    I need to generate an XML output (Content-type: application/xml), but this
    XML output is the XML content which is stored in an XML file. I don't need
    to dinamically generate this XML content.
    I have searched in google but I don't find any catalyst view module for
    managing this case. I don't know if exists any module for generating XML
    output from a static file as, for example, Catalyst::View::XSLT module
    (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm)
    does. That is, generate an output from a static file, in this case, an XML
    output.

    I am not finding much information about designing your own views in
    Catalyst, or at least, I don't see much flexibility. All examples I have
    found need to be generated, through the helper view, with TT template or any
    other templates.
    Is it possible to create your own view, with no template, and for example,
    in my case, read the output from a static file and send this output to the
    client? (I don't know exactly how Views works in Catalyst, though I have
    already read Catalyst tutorial and cookbook)

    Thanks in advanced,


    David

    Well, you could do your own view or just rely on
    Catalyst::Plugin::Static::Simple:

    http://search.cpan.org/~mstrout/Catalyst-Plugin-Static-Simple-0.29/lib/Catalyst/Plugin/Static/Simple.pm#serve_static_file_$file_path

    You could wrap this in a view:

    package MyApp::View::StaticFile;

    use parent 'Catalyst::View';

    sub process {
    my ( $self, $c ) = @_;
    $c->serve_static_file( $c->stash->{static_file} );
    }

    1;



    Then just do $c->forward( $c->view('StaticFile') ); after setting the stash key.

    -Jay

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/




    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100305/5a7bb0de/attachment.htm
  • Jay Shirley at Mar 5, 2010 at 7:10 pm

    On Fri, Mar 5, 2010 at 10:46 AM, David wrote:
    Thanks Jay.

    I thought of that solution too when I had a look at
    Catalyst::Plugin::Static::Simple. But in this case, my doubt was, and is,
    how should I create the view through the helper?
    Most of the examples for creating views are TT views, so they create it as
    'script/hello_create.pl view my_TT_view TT'.

    David

    I'd really recommend just creating a sample application you can mess
    with, like 'catalyst.pl Foo' -- I do this frequently when testing new
    things.

    Then just script/foo_create.pl view StaticFile would create a skeleton view.

    When you supply additional arguments (the "TT") then you are looking
    at basing your view off the helper, which is sourced from
    Catalyst::View::Helper::TT. It's fully optional, and omitting that
    will just create a very basic package.

    Of course you don't have to use any of this, you can just edit
    "lib/MyApp/View/MyView.pm" directly and code it up -- it's just a
    simple perl package (like what I wrote out above).

    -J
  • Ali Mesdaq at Mar 5, 2010 at 6:04 pm
    Maybe I am missing something but why is a view needed? If you are serving up a static file and its xml why don’t you just serve that file statically based on path? Is the header content-type not getting set properly for that file?

    Thanks,
    ------------------------------------------
    Ali Mesdaq (CISSP, GIAC-GREM)
    Sr. Security Researcher
    Websense Security Labs
    http://www.WebsenseSecurityLabs.com<http://www.websensesecuritylabs.com/>
    ------------------------------------------

    From: David
    Sent: Friday, March 05, 2010 5:10 AM
    To: catalyst@lists.scsys.co.uk
    Subject: [Catalyst] Best practices: XML output from static XML

    Hi,

    I need to generate an XML output (Content-type: application/xml), but this XML output is the XML content which is stored in an XML file. I don't need to dinamically generate this XML content.
    I have searched in google but I don't find any catalyst view module for managing this case. I don't know if exists any module for generating XML output from a static file as, for example, Catalyst::View::XSLT module (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm<http://search.cpan.org/%7Ejanus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm>) does. That is, generate an output from a static file, in this case, an XML output.

    I am not finding much information about designing your own views in Catalyst, or at least, I don't see much flexibility. All examples I have found need to be generated, through the helper view, with TT template or any other templates.
    Is it possible to create your own view, with no template, and for example, in my case, read the output from a static file and send this output to the client? (I don't know exactly how Views works in Catalyst, though I have already read Catalyst tutorial and cookbook)

    Thanks in advanced,


    David




    Click here<https://www.mailcontrol.com/sr/wQw0zmjPoHdJTZGyOCrrhg==> to report this email as spam.


    Protected by Websense Hosted Email Security -- www.websense.com
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100305/a1da2ab3/attachment.htm
  • David at Mar 5, 2010 at 6:49 pm
    Well, as Catalyst works under MVC model, I thought that a best practice would be to use a view module although in this case, obiously, the view task is insignificant.

    David




    ________________________________
    De: "Mesdaq, Ali" <amesdaq@websense.com>
    Para: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Enviado: vie,5 marzo, 2010 19:04
    Asunto: RE: [Catalyst] Best practices: XML output from static XML


    Maybe I am missing
    something but why is a view needed? If you are serving up a static file and its
    xml why don’t you just serve that file statically based on path? Is the header
    content-type not getting set properly for that file?

    Thanks,
    ------------------------------------------
    Ali
    Mesdaq (CISSP, GIAC-GREM)
    Sr.
    Security Researcher
    Websense
    Security Labs
    http://www.WebsenseSecurityLabs.com
    ------------------------------------------

    From:David
    Sent: Friday, March 05, 2010 5:10 AM
    To: catalyst@lists.scsys.co.uk
    Subject: [Catalyst] Best practices: XML output from static XML

    Hi,

    I need to generate an XML output (Content-type: application/xml), but this XML
    output is the XML content which is stored in an XML file. I don't need to
    dinamically generate this XML content.
    I have searched in google but I don't find any catalyst view module for
    managing this case. I don't know if exists any module for generating XML output
    from a static file as, for example, Catalyst::View::XSLT module (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm)
    does. That is, generate an output from a static file, in this case, an XML
    output.

    I am not finding much information about designing your own views in Catalyst,
    or at least, I don't see much flexibility. All examples I have found need to be
    generated, through the helper view, with TT template or any other templates.
    Is it possible to create your own view, with no template, and for example, in
    my case, read the output from a static file and send this output to the client?
    (I don't know exactly how Views works in Catalyst, though I have already read
    Catalyst tutorial and cookbook)

    Thanks in advanced,


    David



    Click here to report this email as spam.


    Protected by Websense Hosted Email Security — www.websense.com



    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100305/d8e630b1/attachment.htm
  • Ali Mesdaq at Mar 5, 2010 at 7:31 pm
    To me this sounds like it’s the same issue as serving static images you wouldn’t create a view for that unless you need to wrap it around some application logic. Or at least that’s what it sounds like to me based on the information provided. We could take the MVC concept really far and say that static files need to have a filesystem Model with Controller logic for finding the files and each have their own View for each filetype.

    Thanks,
    ------------------------------------------
    Ali Mesdaq (CISSP, GIAC-GREM)
    Sr. Security Researcher
    Websense Security Labs
    http://www.WebsenseSecurityLabs.com<http://www.websensesecuritylabs.com/>
    ------------------------------------------

    From: David
    Sent: Friday, March 05, 2010 10:49 AM
    To: The elegant MVC web framework
    Subject: Re: [Catalyst] Best practices: XML output from static XML

    Well, as Catalyst works under MVC model, I thought that a best practice would be to use a view module although in this case, obiously, the view task is insignificant.

    David


    ________________________________
    De: "Mesdaq, Ali" <amesdaq@websense.com>
    Para: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Enviado: vie,5 marzo, 2010 19:04
    Asunto: RE: [Catalyst] Best practices: XML output from static XML
    Maybe I am missing something but why is a view needed? If you are serving up a static file and its xml why don’t you just serve that file statically based on path? Is the header content-type not getting set properly for that file?

    Thanks,
    ------------------------------------------
    Ali Mesdaq (CISSP, GIAC-GREM)
    Sr. Security Researcher
    Websense Security Labs
    http://www.WebsenseSecurityLabs.com<http://www.websensesecuritylabs.com/>
    ------------------------------------------

    From: David
    Sent: Friday, March 05, 2010 5:10 AM
    To: catalyst@lists.scsys.co.uk
    Subject: [Catalyst] Best practices: XML output from static XML

    Hi,

    I need to generate an XML output (Content-type: application/xml), but this XML output is the XML content which is stored in an XML file. I don't need to dinamically generate this XML content.
    I have searched in google but I don't find any catalyst view module for managing this case. I don't know if exists any module for generating XML output from a static file as, for example, Catalyst::View::XSLT module (http://search.cpan.org/~janus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm<http://search.cpan.org/%7Ejanus/Catalyst-View-XSLT-0.08/lib/Catalyst/View/XSLT.pm>) does. That is, generate an output from a static file, in this case, an XML output.

    I am not finding much information about designing your own views in Catalyst, or at least, I don't see much flexibility. All examples I have found need to be generated, through the helper view, with TT template or any other templates.
    Is it possible to create your own view, with no template, and for example, in my case, read the output from a static file and send this output to the client? (I don't know exactly how Views works in Catalyst, though I have already read Catalyst tutorial and cookbook)

    Thanks in advanced,


    David





    Click here<https://www.mailcontrol.com/sr/wQw0zmjPoHdJTZGyOCrrhg==> to report this email as spam.


    Protected by Websense Hosted Email Security — www.websense.com<http://www.websense.com>

    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100305/946e8fb7/attachment.htm
  • Jay Shirley at Mar 5, 2010 at 8:20 pm

    On Fri, Mar 5, 2010 at 11:31 AM, Mesdaq, Ali wrote:
    To me this sounds like it?s the same issue as serving static images you
    wouldn?t create a view for that unless you need to wrap it around some
    application logic. Or at least that?s what it sounds like to me based on the
    information provided. We could take the MVC concept really far and say that
    static files need to have a filesystem Model with Controller logic for
    finding the files and each have their own View for each filetype.

    I would say that putting it into a view allows a greater degree of
    future-proof and foresight. Putting it into the controller would work
    fine, up until you need to serve another static file (or a different
    file), or add an access control layer, or switch to use sendfile, or
    switch to start serving from something like MogileFS.

    If you put it all the above in one method, why put it in a controller
    rather than a view?

    In all of what you said you haven't actually said what is wrong with
    using a view.

    I would certainly recommend that serving static files would be done by
    the webserver and render this moot. However, if you want to use
    Catalyst to serve a static file (which would only make sense if there
    *is* application logic) putting this in a View would be the Right Way.

    -Jay
  • Ali Mesdaq at Mar 5, 2010 at 8:42 pm
    " Catalyst to serve a static file (which would only make sense if there *is* application logic) putting this in a View would be the Right Way."

    Yes my point exactly. That?s why I was comparing it to serving static image files and how it's similar to this situation because there seems to be no application logic at all needed for this example so putting it in a view just to follow the design pattern does not make sense to me. That?s why I gave the previous example as an example of overkilling with the design pattern where it really serves no purpose. I completely agree that it makes much more sense to leverage the webserver for dealing with static files when necessary/possible.

    Thanks,
    ------------------------------------------
    Ali Mesdaq (CISSP, GIAC-GREM)
    Sr. Security Researcher
    Websense Security Labs
    http://www.WebsenseSecurityLabs.com
    ------------------------------------------


    -----Original Message-----
    From: J. Shirley
    Sent: Friday, March 05, 2010 12:20 PM
    To: The elegant MVC web framework
    Subject: Re: [Catalyst] Best practices: XML output from static XML
    On Fri, Mar 5, 2010 at 11:31 AM, Mesdaq, Ali wrote:
    To me this sounds like it?s the same issue as serving static images you
    wouldn?t create a view for that unless you need to wrap it around some
    application logic. Or at least that?s what it sounds like to me based on the
    information provided. We could take the MVC concept really far and say that
    static files need to have a filesystem Model with Controller logic for
    finding the files and each have their own View for each filetype.

    I would say that putting it into a view allows a greater degree of
    future-proof and foresight. Putting it into the controller would work
    fine, up until you need to serve another static file (or a different
    file), or add an access control layer, or switch to use sendfile, or
    switch to start serving from something like MogileFS.

    If you put it all the above in one method, why put it in a controller
    rather than a view?

    In all of what you said you haven't actually said what is wrong with
    using a view.

    I would certainly recommend that serving static files would be done by
    the webserver and render this moot. However, if you want to use
    Catalyst to serve a static file (which would only make sense if there
    *is* application logic) putting this in a View would be the Right Way.

    -Jay

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    Protected by Websense Hosted Email Security -- www.websense.com
  • David at Mar 6, 2010 at 2:17 pm
    Exactly, as there is a little bit of application logic, so I need this process.
    Thanks for the solution Jay. I'll go for it.

    Just one last question. When you talk about using 'lib/MyApp/View/MyView.pm', you mean that is also correct to create a simple perl Module for your view. Then implement process method in the View.pm and forward the context from the Controller ( $c->forward( $c->view('MyView') ); )?


    David





    ________________________________
    De: "Mesdaq, Ali" <amesdaq@websense.com>
    Para: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Enviado: vie,5 marzo, 2010 21:42
    Asunto: RE: [Catalyst] Best practices: XML output from static XML

    " Catalyst to serve a static file (which would only make sense if there *is* application logic) putting this in a View would be the Right Way."

    Yes my point exactly. That’s why I was comparing it to serving static image files and how it's similar to this situation because there seems to be no application logic at all needed for this example so putting it in a view just to follow the design pattern does not make sense to me. That’s why I gave the previous example as an example of overkilling with the design pattern where it really serves no purpose. I completely agree that it makes much more sense to leverage the webserver for dealing with static files when necessary/possible.

    Thanks,
    ------------------------------------------
    Ali Mesdaq (CISSP, GIAC-GREM)
    Sr. Security Researcher
    Websense Security Labs
    http://www.WebsenseSecurityLabs.com
    ------------------------------------------


    -----Original Message-----
    From: J. Shirley
    Sent: Friday, March 05, 2010 12:20 PM
    To: The elegant MVC web framework
    Subject: Re: [Catalyst] Best practices: XML output from static XML
    On Fri, Mar 5, 2010 at 11:31 AM, Mesdaq, Ali wrote:
    To me this sounds like it’s the same issue as serving static images you
    wouldn’t create a view for that unless you need to wrap it around some
    application logic. Or at least that’s what it sounds like to me based on the
    information provided. We could take the MVC concept really far and say that
    static files need to have a filesystem Model with Controller logic for
    finding the files and each have their own View for each filetype.

    I would say that putting it into a view allows a greater degree of
    future-proof and foresight. Putting it into the controller would work
    fine, up until you need to serve another static file (or a different
    file), or add an access control layer, or switch to use sendfile, or
    switch to start serving from something like MogileFS.

    If you put it all the above in one method, why put it in a controller
    rather than a view?

    In all of what you said you haven't actually said what is wrong with
    using a view.

    I would certainly recommend that serving static files would be done by
    the webserver and render this moot. However, if you want to use
    Catalyst to serve a static file (which would only make sense if there
    *is* application logic) putting this in a View would be the Right Way.

    -Jay

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    Protected by Websense Hosted Email Security -- www.websense.com

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/




    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100306/3b13ccfa/attachment.htm
  • Jay Shirley at Mar 6, 2010 at 2:34 pm

    On Sat, Mar 6, 2010 at 6:17 AM, David wrote:
    Exactly, as there is a little bit of application logic, so I need this
    process.
    Thanks for the solution Jay. I'll go for it.

    Just one last question. When you talk about using
    'lib/MyApp/View/MyView.pm', you mean that is also correct to create a simple
    perl Module for your view. Then implement process method in the View.pm and
    forward the context from the Controller ( $c->forward( $c->view('MyView') );
    )?


    David
    Yup, that is exactly right.

    -J
  • Bill Moseley at Mar 6, 2010 at 4:25 pm

    On Sat, Mar 6, 2010 at 6:34 AM, J. Shirley wrote:

    Just one last question. When you talk about using
    'lib/MyApp/View/MyView.pm', you mean that is also correct to create a simple
    perl Module for your view. Then implement process method in the View.pm and
    forward the context from the Controller ( $c->forward( $c->view('MyView') );
    )?


    David
    Yup, that is exactly right.
    Expanding this thread a bit...

    I asked a related question in another thread. What if you want a view that
    needs separate code for each action?

    For example, when no template is explicitly defined in the action,
    C::View::TT will pass control to a template based on the action's name.
    Each action can have its own associated template.

    Likewise, for a different type of output I might need code to run for each
    action.

    Say the controller action for the path /music/recent_uploads places a list
    of objects in the stash. Rendering with HTML sends it to TT (e.g
    /templates/music/recent_uploads.tt). But, what if the client wants, say an
    RSS feed or JSON response for that same action? Doesn't that seems like a
    View's job to turn that into a feed or JSON?

    But for both of those examples I need code to serialize those objects in the
    stash (into a feed or JSON). So, my question is 1) how to map the action
    into a view method, and 2) where those view methods should live?

    I don't think a separate view for every possible action is the correct
    approach. Seems better to have in an end() method simply:

    $c->forward( $c->view( $view_type ) );


    A simplistic or naive View approach might look like:

    sub process {
    my ( $self, $c ) = @_;

    my $method = $c->action->reverse;

    $method =~ s{/}{_};

    $self->$method( $c ) if $self->can( $method );
    }

    But, that's flat and ugly.

    I could keep the "view" code in with the controllers which in some way makes
    maintenance easier (related code is together), but then the view is not
    separate.

    my $method = $c->action->name;
    $method .= '_render_json';
    $c->action->controller->$method( $c );


    So, what's the recommended approach to per-action view code?



    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100306/e38651b1/attachment.htm
  • Jay Shirley at Mar 6, 2010 at 8:59 pm

    On Sat, Mar 6, 2010 at 8:25 AM, Bill Moseley wrote:
    On Sat, Mar 6, 2010 at 6:34 AM, J. Shirley wrote:

    Just one last question. When you talk about using
    'lib/MyApp/View/MyView.pm', you mean that is also correct to create a
    simple
    perl Module for your view. Then implement process method in the View.pm
    and
    forward the context from the Controller ( $c->forward(
    $c->view('MyView') );
    )?


    David
    Yup, that is exactly right.
    Expanding this thread a bit...
    I asked a related question in another thread. ?What if you want a view that
    needs separate code for each action?
    For example, when no template is explicitly defined in the action,
    C::View::TT will pass control to a template based on the action's name.
    ?Each action can have its own associated template.
    Likewise, for a different type of output I might need code to run for each
    action.
    Say the controller action for the path /music/recent_uploads places a list
    of objects in the stash. ?Rendering with HTML sends it to TT (e.g
    /templates/music/recent_uploads.tt). ?But, what if the client wants, say an
    RSS feed or JSON response for that same action? ?Doesn't that seems like a
    View's job to turn that into a feed or JSON?
    But for both of those examples I need code to serialize those objects in the
    stash (into a feed or JSON). ?So, my question is 1) how to map the action
    into a view method, and 2) where those view methods should live?
    I don't think a separate view for every possible action is the correct
    approach. ?Seems better to have in an end() method simply:
    $c->forward( $c->view( $view_type ) );

    A simplistic or?naive?View approach might look like:
    sub process {
    ?? ?my ( $self, $c ) = @_;
    ?? ?my $method = $c->action->reverse;
    ?? ?$method =~ s{/}{_};
    ?? ?$self->$method( $c ) if $self->can( $method );
    }
    But, that's flat and ugly.
    I could keep the "view" code in with the controllers which in some way makes
    maintenance easier (related code is together), but then the view is not
    separate.
    my $method = $c->action->name;
    $method .= '_render_json';
    $c->action->controller->$method( $c );

    So, what's the recommended approach to per-action view code?
    I don't think the path taken with Catalyst::Action::REST is the best,
    but it does work very very well in my opinion and I certainly can't
    think of anything better. Being able to send to a serialization
    method based on the content-type solves a lot of these issues. You
    could just setup a content type for your feed in configuration and
    write a custom serialize class and get exactly what you are asking
    for.

    I don't want to evangelize ::REST too much, so to address your
    suggestions more directly I'd have to say that relying on $self->can
    seems a bit too limited for my tastes.

    I'd lean on configuration more so than $self->can. Then a call to
    $self->get_serializer_for('JSON') that returns some serialization
    object (or whatever handler you have) is simple, and coupling it with
    Moose would work very well. Then you can work out adding new
    serialization calls just in config.

    However, I'm having a hard time thinking about any valid use cases for
    this, especially since ::REST does things fairly well (especially for
    how old the code is) so I'd automatically use that for all the cases I
    can think of. Anything else that doesn't fit, I'd just defer to having
    separate views (and possibly a different RenderView+end action as
    appropriate).

    -J
  • Bill Moseley at Mar 6, 2010 at 10:20 pm

    On Sat, Mar 6, 2010 at 12:59 PM, J. Shirley wrote:
    I don't think the path taken with Catalyst::Action::REST is the best,
    but it does work very very well in my opinion and I certainly can't
    think of anything better. Being able to send to a serialization
    method based on the content-type solves a lot of these issues. You
    could just setup a content type for your feed in configuration and
    write a custom serialize class and get exactly what you are asking
    for.
    I agree, ::REST works well for what it does, but doesn't provide a framework
    for a View that is action-specific. ::REST assumes that the actions set an
    entity in the "rest" stash that can be serialized. But, if the same action
    is used for a TT View then probably want to just pass model objects in the
    stash instead of creating a "rest" structure in the stash.

    One could argue that actions should always result in the same data in the
    stash regardless of the View (the Controller has no idea about the final
    View). The reality is that a request to /blob/recent_posts would return
    different data in a JSON response than would be use to render a web page
    with a TT view.



    The "problem" I'm up against is we have an existing application written for
    the web -- so actions expect GET and POST requests and place objects in the
    stash. Then TT uses the objects in the stash to render the markup.

    Now we need to expose these same methods (which means same URLs really) for
    two similar purposes. New development for the web app is all client side.
    Fat AJAX that talks to the application via JSON serialized (mostly)
    requests and responses. Plus, we need to expose a REST API for third party
    customers. So, really it's just an API for both.

    ::REST will work fine for new actions, but there's a lot of existing actions
    that need to work both for TT rendered pages and for JSON responses.

    I think the action's job should be to take a request, validate,
    authenticate, authorize, etc, then either generate error or place model
    objects in the stash. Then pass off to the view to render/serialize.

    The problem is that a request coming from a browser may be slightly
    different than from an AJAX or API request. (Request might come in a as a
    POST on the web and a PUT via the API and parameters might be slightly
    different.) So, either need to dispatch to different actions for same
    request URL or have some kind of filtering code that runs before the action
    to "normalize" the request for the action depending on where it's coming
    from.

    Obviously, it makes sense to share the actions where possible.

    Likewise, the TT View passes control to an action-specific template to
    render the markup for the request, but the same action might need to return
    JSON so in that case would need to also have action-specific code to build
    the json stash from the objects the action fetched.

    I don't want to evangelize ::REST too much, so to address your

    suggestions more directly I'd have to say that relying on $self->can

    seems a bit too limited for my tastes.


    I don't like it either. Still, to me it seems the act of taking the model
    objects loaded by the controller and building the "json" stash is a View
    action -- not something that should happen in the controller action.


    I'd lean on configuration more so than $self->can. Then a call to
    $self->get_serializer_for('JSON') that returns some serialization
    object (or whatever handler you have) is simple, and coupling it with
    Moose would work very well. Then you can work out adding new
    serialization calls just in config.
    So are you suggesting that $self->get_serializer_for('JSON') would return
    code that would be action-specific? That is for a request to
    /blog/recent_posts would return code that would know what to put in the
    "json" stash for that specific request?

    I like the idea of leaning on the configuration implementation -- just not
    sure what that looks like. ;)



    However, I'm having a hard time thinking about any valid use cases for
    this, especially since ::REST does things fairly well (especially for
    how old the code is) so I'd automatically use that for all the cases I
    can think of. Anything else that doesn't fit, I'd just defer to having
    separate views (and possibly a different RenderView+end action as
    appropriate).
    If I was starting fresh I'd be tempted to write all the controller actions
    with ::REST. I'd like it if the various _<METHOD> actions were real actions
    for dispatching (they aren't right?). Real actions would mean could test
    things like Args:

    sub blog_GET : Local Args(1) { # GET requires an argument
    sub blog_POST: Local Args(0) { # POST creates and must not have an
    argument
    sub blog_PUT : Local Args(1) { # PUT requires and argument
    sub blog_DELETE : Local Args(1) {

    Then layer the web app on top -- especially if it's all client side. But,
    again I still think the action's job would be to just place model objects in
    the stash -- not build a "json" structure as that is only needed when the
    response is actually json.



    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100306/be9632f5/attachment.htm
  • Jay Shirley at Mar 6, 2010 at 10:33 pm

    On Sat, Mar 6, 2010 at 2:20 PM, Bill Moseley wrote:
    On Sat, Mar 6, 2010 at 12:59 PM, J. Shirley wrote:

    I don't think the path taken with Catalyst::Action::REST is the best,
    but it does work very very well in my opinion and I certainly can't
    think of anything better. ?Being able to send to a serialization
    method based on the content-type solves a lot of these issues. ?You
    could just setup a content type for your feed in configuration and
    write a custom serialize class and get exactly what you are asking
    for.
    I agree, ::REST works well for what it does, but doesn't provide a framework
    for a View that is action-specific. ?::REST assumes that the actions set an
    entity in the "rest" stash that can be serialized. ?But, if the same action
    is used for a TT View then probably want to just pass model objects in the
    stash instead of creating a "rest" structure in the stash.
    One could argue that actions should always result in the same data in the
    stash regardless of the View (the Controller has no idea about the final
    View). ?The reality is that a request to /blob/recent_posts would return
    different data in a JSON response than would be use to render a web page
    with a TT view.
    This is where I actually really love ::REST. If you make a JSON call,
    then whatever is in the stash key that ::REST is returned to the
    client (via ->status_ok) -- but if you combine this with chained and
    setup other data in the stash, the TT view can access all of that.

    So I view it more that the JSON response is limited to showing *only*
    the request result, where as TT can show everything else surrounding
    it.

    This allows me a great amount of flexibility in my templates, without
    having any [% c.model('Schema::Whatever') %] in them.
    The "problem" I'm up against is we have an existing application written for
    the web -- so actions expect GET and POST requests and place objects in the
    stash. ?Then TT uses the objects in the stash to render the markup.
    Now we need to expose these same methods (which means same URLs really) for
    two similar purposes. ?New development for the web app is all client side.
    ?Fat AJAX that talks to the application via JSON serialized (mostly)
    requests and responses. ?Plus, we need to expose a REST API for third party
    customers. ?So, really it's just an API for both.
    ::REST will work fine for new actions, but there's a lot of existing actions
    that need to work both for TT rendered pages and for JSON responses.
    I think the action's job should be to take a request, validate,
    authenticate, authorize, etc, then either generate error or place model
    objects in the stash. ?Then pass off to the view to render/serialize.
    The problem is that a request coming from a browser may be slightly
    different than from an AJAX or API request. ?(Request might come in a as a
    POST on the web and a PUT via the API and parameters might be slightly
    different.) ?So, either need to dispatch to different actions for same
    request URL or have some kind of filtering code that runs before the action
    to "normalize" the request for the action depending on where it's coming
    from.
    Obviously, it makes sense to share the actions where possible.
    Likewise, the TT View passes control to an action-specific template to
    render the markup for the request, but the same action might need to return
    JSON ?so in that case would need to also have action-specific code to build
    the json stash from the objects the action fetched.
    Just curious, but if you apply the REST action class (and define
    _GET/_POST methods) and keep stash population to your actions, what is
    failing there? I've done similar things to what you are discussing
    (and will again in about a week or two from now) and hadn't run into
    anything severe.

    As long as the content-type (no problem for XmlHttpRequest) is set to
    "application/json" I get back the data I expect. I do have to modify
    some of the actions to set the final stash result, but in most cases
    this is just a single line of code.
    I don't want to evangelize ::REST too much, so to address your

    suggestions more directly I'd have to say that relying on $self->can

    seems a bit too limited for my tastes.
    I don't like it either. ?Still, to me it seems the act of taking the model
    objects loaded by the controller and building the "json" stash is a View
    action -- not something that should happen in the controller action.
    I'd lean on configuration more so than $self->can. ?Then a call to
    $self->get_serializer_for('JSON') that returns some serialization
    object (or whatever handler you have) is simple, and coupling it with
    Moose would work very well. ?Then you can work out adding new
    serialization calls just in config.
    So are you suggesting that?$self->get_serializer_for('JSON') would return
    code that would be action-specific? ?That is for a request to
    /blog/recent_posts would return code that would know what to put in the
    "json" stash for that specific request?
    I like the idea of leaning on the configuration implementation -- just not
    sure what that looks like. ;)
    The very barest example:


    __PACKAGE__->config(
    serializers => {
    'JSON' => sub { return "this is icky, but would work" }
    }
    );
    has 'serializers' => (
    is => 'rw',
    isa => 'HashRef',
    traits => [ 'Hash' ],
    handles => { 'get_serializer_for' => 'get' }
    );

    Then you could do something like:
    $self->get_serializer_for('JSON')->($c);

    (Untested, and I would use coercions to setup a secondary class to
    handle, but again.. at this point just having Views and end actions
    seems more sensible :))
    However, I'm having a hard time thinking about any valid use cases for
    this, especially since ::REST does things fairly well (especially for
    how old the code is) so I'd automatically use that for all the cases I
    can think of. Anything else that doesn't fit, I'd just defer to having
    separate views (and possibly a different RenderView+end action as
    appropriate).
    If I was starting fresh I'd be tempted to write all the controller actions
    with ::REST. ?I'd like it if the various _<METHOD> actions were real actions
    for dispatching (they aren't right?). ?Real actions would mean could test
    things like Args:
    ?? ? sub blog_GET : Local Args(1) { ?# GET requires an argument
    ?? ? sub blog_POST: Local Args(0) ?{ # POST creates and must not have an
    argument
    ?? ? sub blog_PUT : Local Args(1) { ?# PUT requires and argument
    ?? ? sub blog_DELETE : Local Args(1) {
    They aren't normal actions, and they shouldn't be because they're
    handlers for a specific request type. There isn't anything stopping
    you from doing $controller->blog_GET($c) though.

    If you have variable arguments, then you are pointing to a different
    resource and thus what you described wouldn't be REST :)
    Then layer the web app on top -- especially if it's all client side. ?But,
    again I still think the action's job would be to just place model objects in
    the stash -- not build a "json" structure as that is only needed when the
    response is actually json.
  • Bill Moseley at Mar 7, 2010 at 5:03 pm
    On Sat, Mar 6, 2010 at 2:33 PM, J. Shirley wrote:

    This is where I actually really love ::REST. If you make a JSON call,
    then whatever is in the stash key that ::REST is returned to the
    client (via ->status_ok) -- but if you combine this with chained and
    setup other data in the stash, the TT view can access all of that.
    That sounds good. So, what does that exactly look like? Can you help with
    a few examples?

    These are the goals:

    - Don't repeat action code. i.e. don't have separate actions for REST
    and web requests for the same resource.
    - Same URLs for the same data (e.g. /blog/recent_posts) for both the REST
    actions and when rendering with TT.
    - Separate out View from Controller. i.e. don't have actions build data
    structures that won't be used in the response.
    - Web browser requests differ from REST requests, so may need to map the
    request into a common format before running the action.
    - Clean and tidy controllers ;)

    Here's two very simple actions. The first is in a REST app that needs to
    add a TT view. The second is an existing web (browser) action that need to
    extend to accept JSON input and generate JSON output (i.e. convert to using
    ::REST).


    First, here's a pseudo REST action for recent blog posts. How would you
    modify or extend so it works with a TT view?

    Assume that the TT view needs more data from the posts (i.e. include \@posts
    in the stash), and always returns a 200 since the page will always have
    content. Also, the TT view has no need for the "entity" structure created
    in this existing action:

    sub recent_posts : Local ActionClass( 'REST' ) {}

    sub recent_posts_GET {
    my ( $self, $c ) = @_;

    my @posts = map {
    {
    id => $_->id,
    body => $_->description,
    created => $_->created_time->iso8601_with_zone,
    }
    } $c->model( 'Blog::Post' )->recent;

    return @posts
    ? $self->status_ok( $c, entity => { posts => \@posts } )
    : $self->status_no_content( $c ) unless @posts;

    }


    Or going the other direction, here's an existing action used by web browsers
    to view a blog, create a blog, or update an existing one.

    A web form POSTs to /blog to create and POSTs to /blog/1234 to update.
    The request parameters are validated and used to update/create the blog.
    The action builds a "$form" object that used for this purpose and is used by
    TT to render the form.

    Note that a GET to this action works, too. It simply returns a form object
    in the stash which TT can use to display the post (or can get at the blog
    object
    directly with $form->object). But, would be better to chain from an action
    with Args(1).


    sub blog : Path {
    my ( $self, $c, $id ) = @_;

    # is user authorized for this method?
    return $c->res->status( 403 )
    unless $self->authorize( $c ):

    # build form object and place in stash;
    my $form = Form::Blog->new(
    $id, # will be undefined for CREATE
    $c->req->parameters,
    );
    $c->stash->{form} = $form;


    # GET requires an id to a valid blog
    return $c->status( 404 )
    if $c->req->method eq 'GET' && !$form->object;


    # was form POSTed?
    return unless $c->req->method eq 'POST';

    # redisplay page if does not validate
    return unless $form->validate;

    # write data to model
    $form->update_or_create;

    # Redirect to show new post:
    my $uri = $c->uri_for( 'blog', $form->object->id );
    return $c->res->redirect( $uri );
    }



    Now, for REST it's a POST to /blog to create and NO arguments are allowed,
    and for update it's a PUT to /blog/$id and $id is REQUIRED. The request
    parameters are in a "blog_data" key in the JSON request. For create return
    201 with a Location: header. On update probably return a 204.

    If the request parameters do not validate (as tested by the form) then need
    to serialize the form's errors in a JSON response.

    Much of the existing blog action can be used for both the POST and PUT (and
    probably GET), but need to map the "blog_data" into parameters used by the
    form object.

    That seems a bit more straight forward -- just add blog_<$METHOD> methods
    that (re-set) the status code (and for GET) builds the "rest" stash. But,
    still need a way to extract out the "blog_data" from $c->req->data and use
    it as the request parameters.


    Just curious, but if you apply the REST action class (and define
    _GET/_POST methods) and keep stash population to your actions, what is
    failing there? I've done similar things to what you are discussing
    (and will again in about a week or two from now) and hadn't run into
    anything severe.
    The main issue is just finding a clean way to handle both web browser and
    REST request and responses.

    But specifically, two issues:

    First, input munging is often required. I want to share action code for
    processing input data but the web request comes in $c->req->parameters, but
    with ::REST the request data comes in $c->req->data and may be formatted
    slightly differently or with different parameter names.

    Second, the ::REST approach has the controller actions building the "entity"
    structure which feels more like a view operation. Minor point but turning,
    say, a DateTime object into a human-readable format (or ISO8601 for JSON
    response) both seem like views.




    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100307/96b16291/attachment.htm
  • John Karr at Mar 8, 2010 at 9:14 am
    I'm having a problem with deploying a Catalyst application (I'm learning
    Catalyst and this is the first application I've tried to put on the web, and
    it works on my test machine which has a similar configuration to my ISP, but
    just times-out at my isp returning nothing), and need to capture the logging
    output from the fastcgi script to a file instead of the apache log. I
    already tried plugging in Catalyst::Plugin::Log4perl::Simple, while it
    redirects cgi and Catalyst's internal server to a file it does not work
    under fastcgi.

    I would think to replace the Catalyst::Log method _send_to_log which just
    dumps an array of messages to STDERR with one that dumped to a file instead.
    Or capturing STDERR to a Filehandle might be an even easier hack. In a
    simpler environment either of these methods should work, but with Catalyst
    there are issues that are beyond me. One is persistence of a Filehandle
    (either a log file or a captured STDERR), the other is overriding a method
    of an ancestor object throughout the sequence of scripts. Finally there is
    the question of insertion point.
  • Peter Karman at Mar 8, 2010 at 2:32 pm

    John Karr wrote on 03/08/2010 03:14 AM:
    I'm having a problem with deploying a Catalyst application (I'm learning
    Catalyst and this is the first application I've tried to put on the web, and
    it works on my test machine which has a similar configuration to my ISP, but
    just times-out at my isp returning nothing), and need to capture the logging
    output from the fastcgi script to a file instead of the apache log. I
    already tried plugging in Catalyst::Plugin::Log4perl::Simple, while it
    redirects cgi and Catalyst's internal server to a file it does not work
    under fastcgi.
    I use Catalyst::Plugin::Log4perl (no ::Simple) with fcgi and it works.
    Here's my config:

    ############################################################
    # A simple root logger with a Log::Log4perl::Appender::File
    # file appender in Perl.
    ############################################################
    log4perl.rootLoggerÞBUG, LOGFILE

    log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
    log4perl.appender.LOGFILE.filename=/var/log/apache2/myapp.log
    log4perl.appender.LOGFILE.mode=append

    log4perl.appender.LOGFILE.layout=PatternLayout
    log4perl.appender.LOGFILE.layout.ConversionPattern=[%r] %d %c - %m%n



    --
    Peter Karman . http://peknet.com/ . peter@peknet.com
  • Tomas Doran at Mar 8, 2010 at 11:47 pm

    On 8 Mar 2010, at 09:14, John Karr wrote:

    I'm having a problem with deploying a Catalyst application (I'm
    learning
    Catalyst and this is the first application I've tried to put on the
    web, and
    it works on my test machine which has a similar configuration to my
    ISP, but
    just times-out at my isp returning nothing), and need to capture the
    logging
    output from the fastcgi script to a file instead of the apache log.
    Right. That is very likely to indicate that your app isn't getting as
    far as even starting.

    Ergo, redirecting your logging as likely to fail, as your app never
    gets loaded far enough to load a log class.

    I'd recommend finding the error log (you should be able to download it
    from somewhere even if you don't have shell access?)..

    But if all else fails, try something like the attached patch.. That'll
    log compile errors in your app into a known location you can then FTP
    back..

    Good luck!
    t0m


    -------------- next part --------------
    diff --git a/script/foo_fastcgi.pl b/script/foo_fastcgi.pl
    index f38c614..0957a98 100755
    --- a/script/foo_fastcgi.pl
    +++ b/script/foo_fastcgi.pl
    @@ -1,7 +1,15 @@
    #!/usr/bin/env perl

    -use Catalyst::ScriptRunner;
    -Catalyst::ScriptRunner->run('Foo', 'FastCGI');
    +eval {
    + require Catalyst::ScriptRunner;
    + Catalyst::ScriptRunner->run('Foo', 'FastCGI');
    +};
    +
    +if ($@) {
    + open(FAIL, '>/home/myuser/faillog.txt');
    + print FAIL, $@;
    + close(FAIL);
    +}

    1;

    -------------- next part --------------

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedMar 5, '10 at 1:10p
activeMar 8, '10 at 11:47p
posts19
users7
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2021 Grokbase