15

This question is somewhat related to What’s the simplest way to make a HTTP GET request in Perl?.

Before making the request via LWP::Simple I have a hash of query string components that I need to serialize/escape. What's the best way to encode the query string? It should take into account spaces and all the characters that need to be escaped in valid URIs. I figure it's probably in an existing package, but I'm not sure how to go about finding it.

use LWP::Simple;
my $base_uri = 'http://example.com/rest_api/';
my %query_hash = (spam => 'eggs', foo => 'bar baz');
my $query_string = urlencode(query_hash); # Part in question.
my $query_uri = "$base_uri?$query_string";
# http://example.com/rest_api/?spam=eggs&foo=bar+baz
$contents = get($query_uri);
Community
  • 1
  • 1
cdleary
  • 69,512
  • 53
  • 163
  • 191

6 Answers6

28

URI::Escape is probably the most direct answer, as other have given, but I would recommend using a URI object for the entire thing. URI automatically escapes the GET parameters for you (using URI::Escape).

my $uri = URI->new( 'http://example.com' );
$uri->query_form(foo => '1 2', bar => 2);
print $uri; ## http://example.com?foo=1+2&bar=2

As an added bonus, LWP::Simple's get function will take a URI object as it's argument instead of a string.

gpojd
  • 22,558
  • 8
  • 42
  • 71
19

URI::Escape does what you want.

use URI::Escape;

sub escape_hash {
    my %hash = @_;
    my @pairs;
    for my $key (keys %hash) {
        push @pairs, join "=", map { uri_escape($_) } $key, $hash{$key};
    }
    return join "&", @pairs;
}
Leon Timmermans
  • 30,029
  • 2
  • 61
  • 110
5

URI is far simpler than URI::Escape for this. The method query_form() accepts a hash or a hashref:

use URI;
my $full_url = URI->new('http://example.com');
$full_url->query_form({"id" => 27, "order" => "my key"});
print "$full_url\n";     # http://example.com?id=27&order=my+key
5

Use the module URI to build the URL with the query parameters:

use LWP::Simple;
use URI;

my $uri_object = URI->new('http://example.com/rest_api/');
$uri_object->query_form(spam => 'eggs', foo => 'bar baz');

$contents = get("$uri_object");

I found this solution here.

Flimm
  • 136,138
  • 45
  • 251
  • 267
  • Although solutions using map and URI::Escape are elegant ... this seems simplest and thus best to me. – bbarker Jun 05 '15 at 00:06
4

Use LWP::UserAgent instead:

use strict;
use warnings;

use LWP::UserAgent;

my %query_hash = (spam => 'eggs', foo => 'bar baz');

my $ua = LWP::UserAgent->new();
my $resp = $ua->get("http://www.foobar.com", %query_hash);

print $resp->content;

It takes care of the encoding for you.

If you want a more generic encoding solution, see HTML::Entities.

EDIT: URI::Escape is a better choice.

Joe Casadonte
  • 15,888
  • 11
  • 45
  • 57
  • 2
    Why is URI:Escape a better choice? – cdleary Jan 16 '09 at 01:56
  • I may be mistaken, but doesn't HTML::Entities encode things like < to > while URI::Escape escapes things for the URI, like a space to %20. They encode different things, one for HTML, and the other for URI's. – gpojd Jan 16 '09 at 02:32
  • 5
    Unless I'm missing something. This does NOT add a query string to the request URI, it adds in the arguments as HTTP Headers, which is completely different. http://search.cpan.org/~gaas/libwww-perl-5.834/lib/LWP/UserAgent.pm#REQUEST_METHODS – cliveholloway Mar 09 '13 at 17:57
2

URI::Escape is the module you are probably thinking of.

Josh
  • 12,896
  • 4
  • 48
  • 49
SquareCog
  • 19,421
  • 8
  • 49
  • 63