Turn Query String into Hash Perl - perl

I want to find out how to do the opposite of this:
Perl - How can I turn a hash into a query string?
I have a query string form that is stringified and want to convert it to a hash.
With more context, a client is passing some URL params as a stringified query form which is base64 encoded, and I wanted to decode, turn into a hash, add some more custom URL parameters to the hash, then I have a method that already converts back to a string and appends to the URL.
my $uriQuery = URI::Query->new($redirectQueryParams);
$qs = $uriQuery->hash;
Seems to blow up with
Can't locate object method "new" via package "URI::Query"

The URI module in conjunction with the drop-in addon URI::QueryParams can do what you want.
use strict;
use warnings;
use URI;
use URI::QueryParam;
my $uri = URI->new('https://example.org/?foo=bar&baz=qrr');
$uri->query_param_append(frobnication => 'yes, please');
print $uri;
This will print
https://example.org/?foo=bar&baz=qrr&frobnication=yes%2C+please
If you actually wanted a hash, you could call the query_form_hash method.
$uri->query_form_hash
However, that doesn't make much sense considering that all the alterations you could think of are already implemented.

Related

How to receive json in Dancer?

I am very new to Perl framework Dancer. As of now I have a get http listener working. I have an Angular framework trying to post a json string to Dancer. How can I retreive the json and perhaps assign it to a scalar variable ($json).
get '/games' => sub {
header 'Access-Control-Allow-Origin' => '*';
&loadgames();
return $games;
};
post '/newgame' => sub {
header 'Access-Control-Allow-Origin' => '*';
#what should i put here to retrieve the json string
#I plan to pass the json string to a sub to convert to XML
};
I am not sure If I chose Dancer as backend framework that will get and post data.
Thanks for the help!
If your HTTP request has a JSON body (Content-type: application/json) rather than being an HTML form post, then you probably want something like this:
post '/url-path' => {
my $post = from_json( request->body );
# do something with the POSTed data structure
# which would typically be a hashref (or an arrayref)
# e.g.: schema->resultset('Widget')->create($post);
}
The from_json routine is one of the DSL Keywords provided by Dancer.
Dancer provides the params keyword for accessing route, body, and query parameters. You want a body parameter. Exactly which body parameter you want will depend on the name of the field you posted it to the route with (look at your form or your ajax request).
my $json_string = params('body')->{$field_name}
You can also use param, if you don't have any conflicting parameter names in the route or query parameters.
Once you have the json, remember it's just a string at the moment. You might want to read it into a perl data structure: Dancer provides from_json for this purpose.
As an aside: I notice in your get route, you call a function loadgames in void context, and then return a variable you haven't declared (or perhaps you have set it as a global - but do you need it to be a global?). I recommend beginning each perl file with use strict; to pick up issues like this. I suspect you probably just want to use the return value of loadgames as your return value.

Mojo::DOM shortcut to get absolute url for a resource?

When parsing a webpage with Mojo::DOM (or any other framework), it's fairly common to be pulling a resource address that could be either relative or absolute. Is there a shortcut method to translate such a resource address to an absolute URL?
The following mojo command pulls all the stylesheets on mojolicio.us:
$ mojo get http://mojolicio.us "link[rel=stylesheet]" attr href
/mojo/prettify/prettify-mojo-light.css
/css/index.css
And the following script does the same, but also uses URI to translate the resource into an absolute URL.
use strict;
use warnings;
use Mojo::UserAgent;
use URI;
my $url = 'http://mojolicio.us';
my $ua = Mojo::UserAgent->new;
my $dom = $ua->get($url)->res->dom;
for my $csshref ($dom->find('link[rel=stylesheet]')->attr('href')->each) {
my $cssurl = URI->new($csshref)->abs($url);
print "$cssurl\n";
}
Outputs:
http://mojolicio.us/mojo/prettify/prettify-mojo-light.css
http://mojolicio.us/css/index.css
Obviously, a relative URL in this context should be made absolute using the URL that loaded DOM. However, I don't know of a way to get a resource absolute URL except for coding it myself.
There is Mojo::URL #to_abs in Mojolicious. However, I don't know if that would integrate in some way with Mojo::DOM, and by itself would take more code than URI.
My ideal solution would be if something like the following were possible from both a script and command line, but looking for any related insights into using Mojo for parsing:
mojo get http://mojolicio.us "link[rel=stylesheet]" attr href to_abs
I'm not sure why you think it would take more code to use Mojo::URL? In the following example I get the actual request URL from the transaction (there might have been redirects, which I've allowed) which I have called $base.
Then since $base is an instance of Mojo::URL I can create a new instance with $base->new. Of course if that seems to magical, you can replace it with Mojo::URL->new.
use Mojo::Base -strict;
use Mojo::UserAgent;
my $url = 'http://mojolicio.us';
my $ua = Mojo::UserAgent->new->max_redirects(10);
my $tx = $ua->get($url);
my $base = $tx->req->url;
$tx->res
->dom
->find('link[rel=stylesheet]')
->map(sub{$base->new($_->{href})->to_abs($base)})
->each(sub{say});

How do I read URL parameters from flex application in Perl Dancer CGI?

I want to know how to pass input parameter to perl cgi . I have a flex application, it will take name and some other details of a person, then i want to call a perl cgi with these details as input. How it's possible? Is appending parameter at the end of url eg:http://localhost/cgi-bin/test.pl?name=abc&location=adsas ,the only method to pass parameter to perl cgi?
How can i get passed parameter inside perl cgi?
I have tried this code but didn't get output
use CGI qw(:standard);
use strict;
my $query = new CGI;
my $name = $query->param('name');
my $loc = $query->param('loc');
print "$name is from $loc\n";
The client (Flex) is irrelevant. A query string is a query string and post data is post data, no matter what sends it to the server.
If you are using Dancer, then you are using Plack. If CGI is involved, then Plack will take care of it and translate all the environment variables to the standard Plack interface which Dancer will consume.
You can't access the CGI environment variables directly (and nor can CGI.pm).
From the docs:
get '/foo' => sub {
request->params; # request, params parsed as a hash ref
request->body; # returns the request body, unparsed
request->path; # the path requested by the client
# ...
};
Therefore:
my $params = request->params;
my $name = $params->{'name'};
my $loc = $params->{'loc'};

Perl: Programatically set POST param using REST::Client module

I've built a REST Server and now I want to rapidly test it from a Perl Client, using REST::Client module.
It works fine if I perform GET Request (explicitly setting parameters in the URL) but I can't figure out how to set those params in POST Requests.
This is how my code looks like:
#!/usr/bin/perl
use strict;
use warnings;
use REST::Client;
my $client = REST::Client->new();
my $request_url = 'http://myHost:6633/my_operation';
$client->POST($request_url);
print $client->responseContent();
I've tried with something similar to:
$client->addHeader ('my_param' , 'my value');
But it's clearly wrong since I don't want to set an HTTP predefined Header but a request parameter.
Thank you!
It quite straight forward. However, you need to know what kind of content the server expects. That will typically either be XML or JSON.
F.ex. this works with a server that can understand the JSON in the second parameter, if you tell it what it is in the header in the third parameter.
$client->POST('http://localhost:3000/user/0/', '{ "name": "phluks" }', { "Content-type" => 'application/json'});
The REST module accepts a body content parameter, but I found to make it work with a string of parameters, you need to set a proper content type.
So the following code works for me:
$params = $client->buildQuery([username => $args{username},
password => $args{password}]);
$ret = $client->POST('api/rest/0.001/login', substr($params, 1),
{'Content-type' => 'application/x-www-form-urlencoded'});
I've not used the REST module, but looking at the POST function, it accepts a body content parameter, try creating a string of the parameters and send that within the function
$client->POST($request_url, "my_param=my+value");
print $client->responseContent();

What do I gain by filtering URLs through Perl's URI module?

Do I gain something when I transform my $url like this: $url = URI->new( $url )?
#!/usr/bin/env perl
use warnings; use strict;
use 5.012;
use URI;
use XML::LibXML;
my $url = 'http://stackoverflow.com/';
$url = URI->new( $url );
my $doc = XML::LibXML->load_html( location => $url, recover => 2 );
my #nodes = $doc->getElementsByTagName( 'a' );
say scalar #nodes;
The URI module constructor would clean up the URI for you - for example correctly escape the characters invalid for URI construction (see URI::Escape).
The URI module as several benefits:
It normalizes the URL for you
It can resolve relative URLs
It can detect invalid URLs (although you need to turn off the schemeless bits)
You can easily filter the URLs that you want to process.
The benefit that you get with the little bit of code that you show is minimal, but as you continue to work on the problem, perhaps spidering the site, URI becomes more handy as you select what to do next.
I'm surprised nobody has mentioned it yet, but$url = URI->new( $url ); doesn't clean up your $url and hand it back to you, it creates a new object of class URI (or, rather, of one if its subclasses) which can then be passed to other code which requires a URI object. That's not particularly important in this case, since XML::LibXML appears to be happy to accept locations as either strings or objects, but some other modules require you to give them a URI object and will reject URLs presented as plain strings.