Is there a way in Dancer to execute a code after every request?
I tried with an after hook but it seems that it doesn't execute after a file request...
There is a hook called 'after_file_render' which is executed a decent number of times after each request but I am not sure what is its purpose. Is it always called after every request?
The after_file_render hook is run after each successful request for a static file (e.g., a CSS file or an image), while the after hook runs after an action is performed by a route handler.
If you want to run the same code for both after and after_file_render, you can put it in a subroutine and assign it to the two hooks using a reference, e.g.:
sub foo {
...
}
hook after_file_render => \&foo;
hook after => \&foo;
Related
In writing a Sinatra app, I added a function to my config.ru file to automatically use additional controllers, while also running my main Application Controller (last line of code below). All tests passed up until the PATCH edit request, which was not even being recognized in the controller (I tried prying within the request).
See config.ru code below; why would PATCH (and I assume DELETE) not be recognized when using the method below to auto-add controllers? When I added "use SongsController...ect" that is shown at the bottom of my code below, my app worked like a charm. Thanks in advance.
require './config/environment'
if ActiveRecord::Migrator.needs_migration?
raise 'Migrations are pending. Run `rake db:migrate` to resolve the issue.'
end
# auto-add controllers
Dir[File.join(File.dirname(__FILE__), "app/controllers", "*.rb")].collect {|file| File.basename(file).split(".")[0] }.reject {|file| file == "application_controller" }.each do |file|
string_class_name = file.split('_').collect { |w| w.capitalize }.join
class_name = Object.const_get(string_class_name)
use class_name
end
use Rack::MethodOverride
use SongsController
use ArtistsController
use GenresController
run ApplicationController
If your requests are coming from a browser then they will in reality be POST requests, not PATCH or DELETE (as GET and POST are the only methods browsers use). In order to use other HTTP verbs Sinatra relies on the Rack::MethodOverride middleware which converts the request to the correct type if there is a hidden _method parameter.
You have this middleware in your config, but it is after your code to find and add your other controllers. This means that when a request arrives it will not have been modified to be the appropriate type when those controllers see it, and so they will treat it as a POST and not PATCH and ignore it.
The fix is simply to move the line use Rack::MethodOverride to before the code to auto-add your other controllers, so requests are modified before your controllers see them.
I'm working in a section of a Perl module that creates a large CSV response. The server runs on Plack, on which I'm far from expert.
Currently I'm using something like this to send the response:
$res->content_type('text/csv');
my $body = '';
query_data (
parameters => \%query_parameters,
callback => sub {
my $row_object = shift;
$body .= $row_object->to_csv;
},
);
$res->body($body);
return $res->finalize;
However, that query_data function is not a fast one and retrieves a lot of records. In there, I'm just concatenating each row into $body and, after all rows are processed, sending the whole response.
I don't like this for two obvious reasons: First, it takes a lot of RAM until $body is destroyed. Second, the user sees no response activity until that method has finished working and actually sends the response with $res->body($body).
I tried to find an answer to this in the documentation without finding what I need.
I also tried calling $res->body($row_object->to_csv) on my callback section, but seems like that ends up sending only the last call I made to $res->body, overriding all previous ones.
Is there a way to send a Plack response that flushes the content on each row, so the user starts receiving content in real time as the data is gathered and without having to accumulate all data into a veriable first?
Thanks in advance for any comments!
You can't use Plack::Response because that class is intended for representing a complete response, and you'll never have a complete response in memory at one time. What you're trying to do is called streaming, and PSGI supports it even if Plack::Response doesn't.
Here's how you might go about implementing it (adapted from your sample code):
my $env = shift;
if (!$env->{'psgi.streaming'}) {
# do something else...
}
# Immediately start the response and stream the content.
return sub {
my $responder = shift;
my $writer = $responder->([200, ['Content-Type' => 'text/csv']]);
query_data(
parameters => \%query_parameters,
callback => sub {
my $row_object = shift;
$writer->write($row_object->to_csv);
# TODO: Need to call $writer->close() when there is no more data.
},
);
};
Some interesting things about this code:
Instead of returning a Plack::Response object, you can return a sub. This subroutine will be called some time later to get the actual response. PSGI supports this to allow for so-called "delayed" responses.
The subroutine we return gets an argument that is a coderef (in this case, $responder) that should be called and passed the real response. If the real response does not include the "body" (i.e. what is normally the 3rd element of the arrayref), then $responder will return an object that we can write the body to. PSGI supports this to allow for streaming responses.
The $writer object has two methods, write and close which both do exactly as their names suggest. Don't forget to call the close method to complete the response; the above code doesn't show this because how it should be called is dependent on how query_data and your other code works.
Most servers support streaming like this. You can check $env->{'psgi.streaming'} to be sure that yours does.
Plack is middleware. Are you using a web application framework on top of it, like Mojolicious or Dancer2, or something like Apache or Starman server below it? That would affect how the buffering works.
The link above shows an example by Plack's author:
https://metacpan.org/source/MIYAGAWA/Plack-1.0037/eg/dot-psgi/echo-stream-sync.psgi
Or you can do it easily by using Dancer2 on top of Plack and Starman or Apache:
https://metacpan.org/pod/distribution/Dancer2/lib/Dancer2/Manual.pod#Delayed-responses-Async-Streaming
Regards, Peter
Some reading material for you :)
https://metacpan.org/pod/PSGI#Delayed-Response-and-Streaming-Body
https://metacpan.org/pod/Plack::Middleware::BufferedStreaming
https://metacpan.org/source/MIYAGAWA/Plack-1.0037/eg/dot-psgi/echo-stream.psgi
https://metacpan.org/source/MIYAGAWA/Plack-1.0037/eg/dot-psgi/nonblock-hello.psgi
So copy/paste/adapt and report back please
I have a jobque mechanism in ZF.
The jobque simlpy stores the the function call (Class, Method and params) and later executes it as CLI daemon. The daemon works, however at places the application looks for information from the request object, and when called from the CLI these places fail, or get no info.
I would like to store the original request object together with the job and when the job is processed set the request object back as if the job was done by the originall request, somethin along the line of the following pseudo code:
$ser_request = serialize(Zend_Controller_Front::getInstance ()->getRequest ());
-->save to db
-->retrive from db
$ZCF= new Zend_Controller_Front;
$ZCF::getInstance ()->setRequest (unserialize($ser_request))
The aim is to store and replay the jobs later withouth having to change the rest of the application.
Any suggestions how to do that?
I am not sure if this works, but here's an idea. Try to implement _sleep and _wakeup magic methods for the request object. Haven't tried it out, but maybe it's at least a starting solution.
I'm working with SOAP::WSDL and another company's custom WSDL file. Every time they make a change for me and I recreate my modules, something breaks. Finding the problem is rather tedious because I don't find a proper way to access the actual request that is sent to the SOAP server.
The only way to get to the request so far has been to use tcpdump in conjunction with wireshark to extract the request and result. That works, but since I don't have root privileges on the dev machine I have to get an admin over every time I want to do that. I feel there must be another way to get to the HTTP::Request object inside the SOAP::WSDL thing. But if the server returns a fault, I don't even have a response object, but rather a SOAP::WSDL::SOAP::Typelib::Fault11 object that has no visible relation to the request.
I've also tried using the debugger but I'm having trouble finding the actual request part. I've not yet understood how to tell the debuger to skip to a specific part deep inside a complex number of packages.
I stumbled across this, having the same problem myself. I found the answer is using both options that raina77ow listed.
$service->outputxml(1);
returns the whole SOAP envelope xml, but this needs to be combined with
$service->no_dispatch(1);
With no_dispatch set, the SOAP request is printed, instead of the reply from the request. Hopefully this can help others.
Have you tried to use SOAP::WSDL::Client tracing methods - and outputxml in particular? It returns the raw SOAP envelope which is to be sent to the server.
You can also use no_dispatch configuration method of SOAP::WSDL package:
When set, call() returns the plain request XML instead of dispatching
the SOAP call to the SOAP service. Handy for testing/debugging.
I found a way to at least print out the generated XML code.
First, I looked at SOAP::WSDL::Client as raina77ow suggested. That wasn't what I needed, though. But then I came across SOAP::WSDL::Factory::Serializer. There, it says:
Serializer objects may also be passed directly to SOAP::WSDL::Client
by using the set_serializer method.
A little fidgeting and I came up with a wrapper class for SOAP::WSDL::Serializer::XSD which is the default serializer used by SOAP::WSDL. A look at the code helped, too.
Here's the module I wrote. It uses SOAP::WSDL::Serializer::XSD as a base class and overloads the new and serialize methods. While it only passes arguments to new, it grabs the returned XML from serialize and prints it, which suffices for debugging. I'm not sure if there's a way to put it somewhere I can easily get it from.
package MySerializer;
use strict;
use warnings;
use base qw(SOAP::WSDL::Serializer::XSD);
sub new {
my $self = shift;
my $class = ref($self) || $self;
return $self if ref $self;
# Create the base object and return it
my $base_object = $class->SUPER::new(#_);
return bless ($base_object, $class);
}
sub serialize {
my ($self, $args_of_ref) = #_;
# This is basically a wrapper function that calls the real Serializer's
# serialize-method and grabs and prints the returned XML before it
# giving it back to the caller
my $xml = ref($self)->SUPER::serialize($args_of_ref);
print "\n\n$xml\n\n"; # here we go
return $xml;
}
1;
And here's how I call it:
my $serializer = MySerializer->new();
$self->{'_interface'} = Lib::Interfaces::MyInterface->new();
$self->{'_interface'}->set_serializer($serializer); # comment out to deactivate
It's easy to deactivate. Only put a comment in the set_serializer line.
Of course printing a block of XML to the command line is not very pretty, but it gets the job done. I only need it once in a while why coding/testing, so this is fine I guess.
When writing / maintaining web application written in Perl using CGI.pm, how should I handle errors (exceptions)? Webapp in question can be deployed as plain CGI app, as FastCGI app (using CGI::Fast), and as mod_perl app using ModPerl::Registry handler.
I mean here handling errors like page not found, or configuration forbids given action, or some external command used in the app failed (like e.g. cannot connect to the database).
Edit: added 2010-12-14.
The example code flow could look like this:
sub run {
...
run_request();
...
}
sub run_request {
...
$actions{$cgi->param('a')}->();
...
}
sub action_foo {
foo_body()
}
sub foo_body {
check_something()
or handle_error(some description);
}
I mean here that error might have be to be thrown / handled in some nested call, and not only in the action handler / route handler.
Pass the appropriate status code to the header method as per Creating A Standard HTTP Header