POST-запрос с Perl и чтение объекта ответа в маршруте танцора
Попытка написать точную эквивалентность в perl следующего:
curl -H "Content-Type: application/json" -X POST -d '{"user": { "uid":"13453"},"access_token":"3428D3194353750548196BA3FD83E58474E26B8B9"}' https://platform.gethealth.io/v1/health/account/user/
Неопытный с Perl, вот что я пробовал:
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}}]);
};
3 ответа
Я предполагаю, что вы уже работаете с Dancer или добавляете что-то в существующее приложение, и цель состоит в том, чтобы скрыть запрос POST к другому сервису за вашим API.
В вашем примере curl у вас есть Content-Type application/json
, но в вашем Perl-коде вы отправляете форму. Вероятно, это будет Content-Type application/x-www-form-urlencoded
, Это может быть не то, что хочет сервер.
В дополнение к этому, вы передавали данные формы в виде ссылки на массив, что делает POST
считаю, что они заголовки. Это не то, что вы хотите.
Чтобы сделать то же самое, что вы делаете с curl, вам нужно сделать еще несколько шагов.
- Вам необходимо преобразовать данные в JSON. К счастью, Dancer приносит хорошее ключевое слово DSL
to_json
это легко сделать. - Вы должны указать LWP::UserAgent использовать правильный заголовок Content-Type. Это
application/json
и вы можете установить его либо на уровне запроса, либо по умолчанию для объекта пользовательского агента. Я сделаю первое. - Кроме того, я рекомендую не использовать HTTP::Request::Common для импорта ключевых слов в приложение Dancer.
GET
а такжеPOST
и так далее в верхнем регистре, и Dancer DSL имеетget
а такжеpost
который в нижнем регистре, но это все еще сбивает с толку. Вместо этого используйте http://p3rl.org/HTTP::Request явно.
Вот последняя вещь.
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
};
Попробуйте использовать HTTP::Tiny (это на CPAN). ИМХО, это гораздо более чистый модуль, чем LWP::UserAgent, хотя последний гораздо популярнее.
Вот код, который должен работать из коробки:
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'};
Удачи с проектом!
Вот решение с правильным форматом и структурой размещенных параметров:
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;
};