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 приносит хорошее ключевое слово DSLto_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;
};
Другие вопросы по тегам