koba::blog

小林聡: プログラマです

HTTP::Request::Common をより使いやすくする

HTTP::Request::CommonHTTP::Requestインスタンスを生成する簡易な方法ですが、2つ不満がありました。

  1. GET のパラメータをURLエンコードするのが面倒
  2. POST でファイルアップロードするときの構文が特殊なのがかっこう悪い

なので、HTTP::Request::Common をさらに簡便に使えるように前処理の関数を書いてみた。

use strict;
use HTTP::Request::Common 5.814 qw(HEAD GET POST PUT DELETE);

sub _url_encode {
    local $_ = shift;
    s/([^\w\-\*\.\~])/sprintf('%%%02X', unpack('C', $1))/ge;
    $_;
}

sub request {
    my $method = shift;
    my $url    = shift;
    my ($param, @header);
    while (my $key = shift) {
        $param = $key and next    if (ref $key eq 'ARRAY');
        push(@header, $key, shift);
    }
    if ($method eq 'POST') {
        return (grep { ref $_ eq 'ARRAY' } @$param)
            ? POST $url, Content_Type => 'form-data',
                         Content      => $param,
                         @header
            : POST $url, $param, @header;
    }
    else {
        my $query;
        while (my $key = _url_encode(shift @$param)) {
            my $value = _url_encode(shift @$param);
            $query .= $query ? "&$key=$value" : "?$key=$value";
        }
        return $method eq 'HEAD'   ? HEAD   "$url$query", @header :
               $method eq 'GET'    ? GET    "$url$query", @header :
               $method eq 'PUT'    ? PUT    "$url$query", @header :
               $method eq 'DELETE' ? DELETE "$url$query", @header :
                                     undef;
    }
}

以下の形式で、request() を呼出すと、HTTP::Request::Common を使って HTTP::Request のインスタンスを生成します。

HEAD, GET, PUT, DELETE およびファイルアップロード以外の POST の場合

my $request = request(   
    GET => 'http://example.com/path',
    Header1  => 'header1 value',
    Header2  => 'header2 value',
    [ param1 => 'param1 value',
      param2 => 'param2 value'  ]
);

ファイルアップロードの場合

my $request = request(   
    POST => 'http://example.com/path',
    Header1  => 'header1 value',
    Header2  => 'header2 value',
    [ param1 => 'param1 value',
      param2 => [ 'path/filename' ]  ]
);