How to make the post request in BOX API using LWP::UserAgent? - perl

I have tried the following code
my $url = "https://api.box.com/2.0/users/";
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common qw{ POST };
use CGI;
my $ua = LWP::UserAgent->new();
my $request = POST( $url, [ 'name' => 'mkhun', 'is_platform_access_only' => 'true',"Authorization" => "Bearer <ACC TOK>" ] );
my $content = $ua->request($request)->as_string();
my $cgi = CGI->new();
print $cgi->header(), $content;
The above code always give the 400 error. And throwing the
{"type":"error","status":400,"code":"bad_request","context_info":{"errors":[{"reason":"invalid_parameter","name":"entity-body","message":"Invalid value 'is_platform_access_only=true&Authorization=Bearer+WcpZasitJWVDQ87Vs1OB9dQedRVyOrs6&name=mkhun'. Entity body should be a correctly nested resource attribute name\/value pair"}]},
I don't know what is the issue. The same thing with Linux curl is working.
curl https://api.box.com/2.0/users \
-H "Authorization: Bearer <TOKEN>" \
-d '{"name": "Ned Stark", "is_platform_access_only": true}' \
-X POST

The Box API documentation says:
Both request body data and response data are formatted as JSON.
Your code is sending form-encoded data instead.
Also, it looks like Authorization is supposed to be an HTTP header, not a form field.
Try this instead:
use strict;
use warnings;
use LWP::UserAgent;
use JSON::PP;
my $url = "https://api.box.com/2.0/users/";
my $payload = {
name => 'mkhun',
is_platform_access_only => \1,
};
my $ua = LWP::UserAgent->new;
my $response = $ua->post(
$url,
Authorization => 'Bearer <TOKEN>',
Content => encode_json($payload),
);

Related

Curl to Perl HTTP Request

Guys I need this curl request be translated to LWP::UserAgent HTTP Request
echo 'test{test="test"} 3' | curl -v --data-binary #- http://localhost:9090/api/metrics
What I've tried is this :
my $ua = LWP::UserAgent->new;
my $res = $ua->post('http://localhost:9090/api/metrics', ['test{test="test"}' => 3]);
die Dumper $res
But the response says
'_rc' => '400',
'_msg' => 'Bad Request',
'_content' => 'text format parsing error in line 1: unexpected end of input stream
You can try use the following POST request:
use feature qw(say);
use strict;
use warnings;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
my $res = $ua->post('http://localhost:9090/api/metrics', Content => 'test{test="test"} 3');
if ($res->is_success) {
say $res->decoded_content;
}
else {
die $res->status_line;
}
And, since you didn't ask, here's a Mojo example:
use v5.10;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new();
my $tx = $ua->post(
'http://httpbin.org/post',
=> 'test{test="test"} 3'
);
if ($tx->result->is_success) {
say $tx->result->body;
}
else {
die $tx->result->code;
}
It's basically the same as LWP except that Mojo returns a transaction object so you can play with the request too. It's something I wanted in LWP even before Mojo existed.

POST request with Perl and read response object within dancer route

Trying to write the exact equivalence in perl of the following:
curl -H "Content-Type: application/json" -X POST -d '{"user": { "uid":"13453"},"access_token":"3428D3194353750548196BA3FD83E58474E26B8B9"}' https://platform.gethealth.io/v1/health/account/user/
Unexperienced with perl, this is what I have tried:
use HTTP::Request::Common;
use LWP::UserAgent;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
$ua->request(POST 'https://platform.gethealth.io/v1/health/account/user', [{"user": { "uid":param("id")},"access_token":config->{gethealthtoken}}]);
};
I take it you are working with Dancer already, or you are adding something to an existing application, and the goal is to hide the POST request to another service behind your API.
In your curl example, you have the Content-Type application/json, but in your Perl code you are sending a form. That's likely going to be the Content-Type application/x-www-form-urlencoded. It might not be what the server wants.
In addition to that, you were passing the form data as an array reference, which makes POST believe they are headers. That not what you want.
In order to do the same thing you are doing with curl, you need a few more steps.
You need to convert the data to JSON. Luckily Dancer brings a nice DSL keyword to_json that does that easily.
You need to tell LWP::UserAgent to use the right Content-Type header. That's application/json and you can set it either at the request level, or as a default for the user agent object. I'll do the former.
In addition to that, I recommend not using HTTP::Request::Common to import keywords into a Dancer app. GET and POST and so on are upper-case and the Dancer DSL has get and post which is lower-case, but it's still confusing. Use HTTP::Request explicitly instead.
Here's the final thing.
use LWP::UserAgent;
use HTTP::Request;
get '/gethealthadduser/:id' => sub {
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user',
[ 'Content-Type' => 'application/json' ], # headers
to_json { user => param("id"), access_token => config->{gethealthtoken} }, # content
);
my $res = $ua->request($req);
# log the call with log level debug
debug sprintf( 'Posted to gethealth.io with user %s and got a %s back.',
param('id'),
$res->status_line
);
# do things with $res
};
Try using HTTP::Tiny (it's on CPAN). IMHO, it's a much cleaner module than LWP::UserAgent, although the latter is much more popular.
Here's some code that should work out of the box:
use HTTP::Tiny 0.064; # use a recent version or better
my $url = 'https://api.somewhere.com/api/users';
my $data = {
first_name => "joe",
last_name => "blow"
};
my $method = 'POST';
my $default_headers = {
'Authorization' => "Bearer ".$token, # if needed
'Accept' => 'application/json'
};
my $tiny = HTTP::Tiny->new(
agent => 'mywebsite.com',
default_headers => $default_headers,
timeout => 30
);
my $response;
if ( ($method eq 'POST') || ($method eq 'PUT') ) {
$response = $tiny->request($method, $url, {
headers => {
'Content-Type' => 'application/json'
},
content => &toJSON($data)
});
}
else {
if ($data) {
die "data cannot be included with method $method";
}
$response = $tiny->request($method, $url);
}
die unless $response->{'success'};
Good luck on your project!
Here is the solution with the correct format and structure of posted parameters:
get '/api/gethealthadduser/:id' => sub {
my %user = (
uid => param("id")
);
# my $user = {
# uid => param("id")
# };
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(
POST => 'https://platform.gethealth.io/v1/health/account/user/',
[ 'Content-Type' => 'application/json' ], # headers
JSON::to_json({ user => \%user, access_token => config->{gethealthtoken} }) # content
);
my $res = $ua->request($req);
print STDERR Dumper($res);
$res;
};

Get access token in perl

There is a working sample of getting token in bash
response=$(curl --fail --silent --insecure --data "username=test&password=test" \
--header "Authorization: Basic Y2xvdWQtYmVzcG9rZTo=" \
-X POST "https://lab7.local:8071/auth/token?grant_type=password")
token=`echo "$response" | awk '/access_token/{print $NF}' |sed 's/\"//g'`
echo $token
I'm trying to translate it in perl, but getting code 400
#!/usr/bin/env perl
use strict;
use warnings;
use HTTP::Request;
use LWP::UserAgent;
use LWP::Simple;
use JSON::XS;
use Try::Tiny;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(POST => "https://lab7.local:8071/auth/token?grant_type=password");
my $post_data = "username=test&password=test";
$req->content($post_data);
my $resp = $ua->request($req);
if ($resp->is_success) {
my $mess = $resp->decoded_content;
print "$mess\n";
} else {
my $code = $resp->code;
print $code;
}
Your curl version is sending an Authentication header that is missing from the Perl version. You should add that.
$req->header(Authorization => 'Basic Y2xvdWQtYmVzcG9rZTo=');
You're adding a basic auth header, with a username. That string is just the base 64 encoded equivalent.
So you should probably include this in your LWP:
$req -> authorization_basic ( 'cloud-bespoke' );
And it should work.

net::oauth return 401 unauthorized even though curl works

I am attempting to request a token from https://launchpad.net, according to the docs all it wants is a POST to /+request-token with the form encoded values of oauth_consumer_key, oauth_signature, and oauth_signature_method. Providing those items via curl works as expected:
curl --data "oauth_consumer_key=test-app&oauth_signature=%26&oauth_signature_method=PLAINTEXT" https://launchpad.net/+request-token
However, when i attempt to do it through my perl script it is giving me a 401 unauthorized error.
#!/usr/bin/env perl
use strict;
use YAML qw(DumpFile);
use Log::Log4perl qw(:easy);
use LWP::UserAgent;
use Net::OAuth;
$Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;
use HTTP::Request::Common;
use Data::Dumper;
use Browser::Open qw(open_browser);
my $ua = LWP::UserAgent->new;
my ($home) = glob '~';
my $cfg = "$home/.lp-auth.yml";
my $access_token_url = q[https://launchpad.net/+access-token];
my $authorize_path = q[https://launchpad.net/+authorize-token];
sub consumer_key { 'lp-ua-browser' }
sub request_url {"https://launchpad.net/+request-token"}
my $request = Net::OAuth->request('consumer')->new(
consumer_key => consumer_key(),
consumer_secret => '',
request_url => request_url(),
request_method => 'POST',
signature_method => 'PLAINTEXT',
timestamp => time,
nonce => nonce(),
);
$request->sign;
print $request->to_url;
my $res = $ua->request(POST $request->to_url, Content $request->to_post_body);
my $token;
my $token_secret;
print Dumper($res);
if ($res->is_success) {
my $response =
Net::OAuth->response('request token')->from_post_body($res->content);
$token = $response->token;
$token_secret = $response->token_secret;
print "request token ", $token, "\n";
print "request token secret", $token_secret, "\n";
open_browser($authorize_path . "?oauth_token=" . $token);
}
else {
die "something broke ($!)";
}
I tried both with $request->sign and without it as i dont think that is required during the request token phase. Anyway any help with this would be appreciated.
Update, switched to LWP::UserAgent and had to pass in both POST and Content :
my $res = $ua->request(POST $request->to_url, Content $request->to_post_body);
Thanks
Sorry I'm not able to verify from my tablet but with recent Perl you should install and use
use LWP::Protocol::https;
http://blogs.perl.org/users/brian_d_foy/2011/07/now-you-need-lwpprotocolhttps.html

How to make a HTTP PUT request using LWP?

I'm trying to change this request to a HTTP PUT request, any idea how ?
my $request = LWP::UserAgent->new;
my $response =
$request->get($url, "apikey", $apiKey, "requestDate", $requestDate);
You should use HTTP::Request:
use LWP::UserAgent;
use HTTP::Request;
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new("PUT", $url);
my $res = $ua->request($req);
As of 6.04, LWP::UserAgent has a put helper, so you can now do:
$ua->put( $url )
PUT is HTTP::Request::Common. You can build the request first and pass it into user agent.
use HTTP::Request::Common;
use LWP;
$agent = LWP::UserAgent->new;
$request = HTTP::Request::Common::PUT($url, "apikey", $apiKey, "requestDate", $requestDate);
$response = $agent->request($request);