views:

1144

answers:

4

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);
+10  A: 

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
Hynek -Pichi- Vychodil
I though of doing that too, but nesting maps just didn't look right to me.
Leon Timmermans
Map inside for(each) with push sounds same complicated for me but it introduce unneeded temporary variable.
Hynek -Pichi- Vychodil
+1  A: 

URI::Escape is the module you are probably thinking of. http://search.cpan.org/~gaas/URI-1.37/URI/Escape.pm

SquareCog
+6  A: 

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
Why is URI:Escape a better choice?
cdleary
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
+5  A: 

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://google.com" );
$uri->query_form(foo => "1 2", bar => 2);
print $uri; ## http://google.com?foo=1+2&amp;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
I think this is the best solution.
singingfish