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);

5 Answers 5

31

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 its argument instead of a string.

Sign up to request clarification or add additional context in comments.

Comments

17

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;
}

3 Comments

Shortly: sub escape_hash{my %h = @_; return join '&', map{join '=', map uri_escape($_), $_, $h{$_}} keys %h}
I though of doing that too, but nesting maps just didn't look right to me.
Map inside for(each) with push sounds same complicated for me but it introduce unneeded temporary variable.
6

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

Comments

6

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.

1 Comment

Although solutions using map and URI::Escape are elegant ... this seems simplest and thus best to me.
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.