File Coverage

blib/lib/Plack/Middleware/FormatOutput.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::FormatOutput;
2              
3 1     1   15427 use 5.006;
  1         3  
  1         41  
4 1     1   4 use strict;
  1         1  
  1         28  
5 1     1   4 use warnings FATAL => 'all';
  1         7  
  1         39  
6              
7 1     1   472 use parent qw( Plack::Middleware );
  1         228  
  1         4  
8              
9             use HTTP::Exception '4XX';
10              
11             use JSON::XS;
12             use YAML::Syck;
13              
14             =head1 NAME
15              
16             Plack::Middleware::FormatOutput - Format output struct by Accept header.
17              
18             =head1 VERSION
19              
20             Version 0.01
21              
22             =cut
23              
24             our $VERSION = '0.01';
25              
26              
27             =head1 SYNOPSIS
28              
29             use Plack::Middleware::FormatOutput;
30              
31             builder {
32             enable 'FormatOutput';
33             mount "/api" => sub { return {'link' => 'content'} };
34             };
35              
36             =head1 DESCRIPTION
37              
38             The Middleware formats output perl struct by "Accept" header param.
39              
40             For complete RestAPI in Perl use:
41              
42             =over 4
43              
44             =item * Plack::Middleware::RestAPI
45              
46             =item * Plack::Middleware::SetAccept
47              
48             =item * Plack::Middleware::ParseContent
49              
50             =back
51              
52             =head1 CONSTANTS
53              
54             =head2 DEFAULT MIME TYPES
55              
56             =over 4
57              
58             =item * application/json
59              
60             =item * text/yaml
61              
62             =item * text/plain
63              
64             =item * text/html - it uses HTML::Vis as default formater if installed
65              
66             =back
67              
68             =cut
69              
70             ### Set HTML::Vis
71             my $htmlvis = undef;
72              
73             ### Try load library
74             sub _try_load {
75             my $mod = shift;
76             eval("use $mod; 1") ? return 1 : return 0;
77             }
78              
79             ### Set default mime types
80             my $MIME_TYPES = {
81             'application/json' => sub { JSON::XS->new->utf8->allow_nonref->encode($_[0]) },
82             'text/yaml' => sub {
83             local $Data::Dumper::Indent=1; local $Data::Dumper::Quotekeys=0; local $Data::Dumper::Terse=1; local $Data::Dumper::Sortkeys=1;
84             Dump($_[0])
85             },
86             'text/plain' => sub {
87             local $Data::Dumper::Indent=1; local $Data::Dumper::Quotekeys=0; local $Data::Dumper::Terse=1; local $Data::Dumper::Sortkeys=1;
88             Dump($_[0])
89             },
90             'text/html' => sub {
91             if ($htmlvis){
92             return $htmlvis->html($_[0]);
93             }else{
94             return @_;
95             }
96             }
97             };
98              
99             =head1 PARAMETERS
100              
101             =head2 mime_type
102              
103             Specify if and how returned content should be formated in browser.
104              
105             For example:
106              
107             use Plack::Middleware::FormatOutput;
108             use My::HTML
109              
110             builder {
111             enable 'FormatOutput', mime_type => {
112             'text/html' => sub{ My::HTML::Parse(@_) }
113             };
114             mount "/api" => sub { return {'link' => 'content'} };
115             };
116              
117             =head2 htmlvis (if HTML::Vis is installed)
118              
119             Define parameters for HTML::Vis.
120              
121             For example:
122              
123             use Plack::Middleware::FormatOutput;
124              
125             builder {
126             enable 'FormatOutput', htmlvis => {
127             links => 'My::Links'
128             };
129             mount "/api" => sub { return {'link' => 'content'} };
130             };
131              
132             =cut
133              
134             sub prepare_app {
135             my $self = shift;
136              
137             ### Add new mime types
138             foreach my $par (keys %{$self->{mime_type}}){
139             next unless ref $self->{mime_type}{$par} eq 'CODE';
140             $MIME_TYPES->{$par} = $self->{mime_type}{$par};
141             }
142              
143             ### Add htmlvis
144             if (_try_load('HTML::Vis')){
145             my $params = $self->{htmlvis} if exists $self->{htmlvis};
146             $htmlvis = HTML::Vis->new($params);
147             }
148              
149             }
150              
151             sub call {
152             my($self, $env) = @_;
153              
154             # Get accept
155             my $accept = $env->{HTTP_ACCEPT};
156              
157             # Run app
158             my $ret = $self->app->($env);
159              
160             # Return if not content
161             if (!defined $ret){
162             return ['200', ['Content-Type' => $accept], []];
163             }
164              
165             ### Transform returned perl struct by accept
166             my $res;
167             if (exists $MIME_TYPES->{$accept}){
168              
169             # modify response - add forms
170             $res = $MIME_TYPES->{$accept}->($ret);
171              
172             }else{
173             HTTP::Exception::406->throw();
174             }
175              
176             return ['200', ['Content-Type' => $accept, 'Content-Length' => length($res) ], [ $res ]];
177             }
178              
179             =head1 TUTORIAL
180              
181             L
182              
183             =head1 AUTHOR
184              
185             Vaclav Dovrtel, C<< >>
186              
187             =head1 BUGS
188              
189             Please report any bugs or feature requests to github repository.
190              
191             =head1 ACKNOWLEDGEMENTS
192              
193             Inspired by L
194              
195             =head1 REPOSITORY
196              
197             L
198              
199             =head1 LICENSE AND COPYRIGHT
200              
201             Copyright 2015 Vaclav Dovrtel.
202              
203             This program is free software; you can redistribute it and/or modify it
204             under the terms of either: the GNU General Public License as published
205             by the Free Software Foundation; or the Artistic License.
206              
207             See L for more information.
208              
209             =cut
210              
211             1; # End of Plack::Middleware::FormatOutput