One thing I've noticed about the web APIs I'm seeing online is that you can often determine what format you want it in. For example, the API URL is something like
example.com/api/v1/feed
which gives you RSS, but if you want it in ATOM, you can get it at example.com/api/v1/feed/atom
. Want JSON? example.com/api/v1/feed/json
. This way, your Javascript can AJAX that mess up, while your users can pull it into EXCEL with example.com/api/v1/feed/csv
and be happy.
This is cool. So I wrote some Perl to automate that stuff for me.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package API ; | |
use 5.010 ; | |
use strict ; | |
use warnings ; | |
use CGI ; | |
use Exporter 'import' ; | |
use Data::Dumper ; | |
use JSON ; | |
use YAML ; | |
our @EXPORT ; | |
our @EXPORT_OK ; | |
our %EXPORT_TAGS ; | |
BEGIN { | |
our @EXPORT = qw{ | |
export_determined | |
} ; | |
} | |
sub export_determined { | |
my ( $ref , $cgi , $disposition) = @_ ; | |
my $path_info = $cgi->path_info ; | |
my @path_info = split m{/} , $path_info ; | |
if ( lc $path_info[1] eq 'yaml' ) { | |
say 'content-type: application/x-yaml' ; | |
say join '' , | |
'content-disposition: attachment;filename=' , | |
$disposition , | |
'.yaml' if $disposition ; | |
say '' ; | |
print Dump( $ref ) ; | |
} | |
elsif ( lc $path_info[1] eq 'csv' ) { | |
say 'content-type: application/csv' ; | |
say join '' , | |
'content-disposition: attachment;filename=' , | |
$disposition , | |
'.csv' if $disposition ; | |
say '' ; | |
if ( ref $ref eq 'ARRAY' ) { | |
for my $line ( @$ref ) { | |
say join ',' , @$line ; | |
} | |
return ; | |
} | |
if ( ref $ref eq 'HASH' ) { | |
my ( $k ) = keys %$ref ; | |
my $key = $ref->{ $k } ; | |
my @headers = keys %$key ; | |
say join ',' , @headers ; | |
for my $k ( sort keys %$ref ) { | |
say join ',' , | |
map { | |
$ref->{ $k }->{ $_ } || '' | |
} | |
@headers ; | |
} | |
return ; | |
} | |
} | |
elsif ( lc $path_info[1] eq 'xml' ) { | |
say 'content-type: application/xml' ; | |
say join '' , | |
'content-disposition: attachment;filename=' , | |
$disposition , | |
'.xml' if $disposition ; | |
say '' ; | |
print 'undef' ; | |
} | |
elsif ( lc $path_info[1] eq 'dump' ) { | |
say 'content-type: text/plain' ; | |
say join '' , | |
'content-disposition: attachment;filename=' , | |
$disposition , | |
'.txt' if $disposition ; | |
say '' ; | |
print Dumper $ref ; | |
} | |
else { | |
# json | |
say 'content-type: application/json' ; | |
say join '' , | |
'content-disposition: attachment;filename=' , | |
$disposition , | |
'.json' if $disposition ; | |
say '' ; | |
print encode_json $ref ; | |
} | |
} | |
'version 1' ; |
This does not do JSONP, because I'm not expecting, right now, to want to cross-site script the stuff I'm exporting right now. But maybe. And it shouldn't be too bad of a modification. And this is a naive and potentially stupid way of doing CSV. Maybe wrapping everything in quotes?
The cool step would be to make a dispatch table and function refs to the right thing, pulling the magic for each format out. This might be done later.