nt; filename = pictures.csv');

$headers->content_type('text/csv; charset = UTF-8'); # Render data return $self->render(data => $content);

};

app->start;

Use the Text::CSV::Encoded module to create CSV data. The only way to convert the data of one record to a row is to use the print method, which is a method for printing to a filehandle. Therefore, Perl's scalar input/output function is used to output to a scalar variable.

You can name the file using the Content-Disposition header. Let's also specify the Content-Type so that we can see that it is CSV data. When drawing, CSV data is binary data (not an decoded string), so use the data option.

Specify the class that describes the template when drawing

You can specify template_class as an argument of the render method for the class that describes the template when drawing.

$c->render(template_class => $class);

This is very useful if you want to write the template directly in a plugin etc. Mojolicious plugins are very flexible and allow you to write and incorporate the web application itself.

package Mojolicious::Plugin::Viewer;
use Mojo::Base 'Mojolicious::Plugin';

sub register {
  my ($self, $app, $conf) = @_;
  
  my $r = $app->route;
  $r->get('/ viewer', sub {
     my $self = shift;
     # Specify template class
     return $self->render(template_class => __PACKAGE__);
  });
}

1;

__DATA__

@@viewer.html.ep
<html>
  <head>
    <title> Viewer </title>
  <body>
     Viewer <%= lc'A' %>
  </body>
</html>

Dynamically deliver large files

What if you want to dynamically deliver large files in your web application? For example, if you don't know the data size and want to distribute it part by part. If you put everything on the memory, the memory may be overwhelmed, so I don't want to put everything on the memory.

In such a case, use HTTP chunk encoding and distribute part by part. When viewed from the browser, it looks like a single file in the end, so there is no problem.

This can be achieved by combining a method called write_chunk and a callback.

get'/ sizeunknowndata' => sub {
  my $self = shift;

  my $file = 'foo.tar.gz';
  open my $fh, '<', $file
    or die "Error";

  # Write chunk
  $self->res->headers->content_type('application/gzip');
  $self->res->headers->content_disposition(qq/attachment; filename = "$file" /);
  my $cb;
  $cb = sub {
    my $c = shift;
    my $size = 500 * 1024;
    my $length = sysread($fh, my $buffer, $size);
    unless (defined $length) {
      close $fh;
      undef $cb;
      return;
    }
    $c->write_chunk($buffer, $cb);
  };
  $self->$cb;
};

When there is no more data to read, close the filehandle, undefine $cb and remove the reference.

Addendum

The title "Deliver a large file" was misleading. Changed the title to "Deliver large files dynamically".

Large static files can usually be delivered under "public" without straining memory. Also, Mojolicious is an asynchronous I/O, so processing will not be blocked.

Draw a 404 Not Found page

Use reply->not_found to draw a 404 Not found page (the page to display when the page is not found). Twice

get'/' => sub {
  my $sefl = shift;
  
  # If you want to draw a page with 404 not found
  if (...) {
    return $self->reply->not_found;
  }

  $self->render;
}

Changes in Mojolicious 6

The rendering of the 404 Not Found page has changed from render_not_found to reply->not_found.

Draw exception (error) page

You may want to show the error page to the user if something goes wrong with unintended processing. Use reply->exception to draw such a page. Twice

get'/' => sub {
  my $sefl = shift;
  
  # Draw exception (error) page
  if (...) {
    return $self->reply->exception;
  }

  $self->render;
}

Changes in Mojolicious 6

The render_exception method for rendering exception pages has been changed to reply->exception.

How to use JSON::XS to draw JSON

Mojolicious has its own module that draws JSON called Mojo::JSON, which is written in pure Perl. If you want to use JSON::XS to draw JSON fast, I think it's a good idea to replace the handler for JSON as follows.

use Mojolicious::Lite;
use Mojo::JSON::XS;

# Replace handler for drawing json
app->renderer->add_handler(json => sub {
  my ($self, $c, $output, $options) = @_;
  $$output = Mojo::JSON::XS->new->encode($options->{json});
});

get'/' => sub {
  my $self = shift;
  
  $self->render(json => {name =>'kimoto'});
};

app->start;

Mojo::JSON::XS is a module that has the same interface as Mojo::JSON and uses JSON::XS internally. It's included in a package called Mojo::JSON::Any, so install it when you use it.

cpan Mojo::JSON::Any

Related Informatrion