Skip Menu |

This queue is for tickets about the Role-REST-Client CPAN distribution.

Report information
The Basics
Id: 118413
Status: resolved
Priority: 0/
Queue: Role-REST-Client

People
Owner: KAARE [...] cpan.org
Requestors: abraxxa [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.18
Fixed in: 0.19



Subject: set_persistent_header isn't used in next request
I'm using it against an API that requires a POST call against one endpoint with basic auth to get an access-token which has to be included in every API call from there on. Setting the header using set_header works, but is only used for the next request. Setting it using set_persistent_header doesn't use it for the next but subsequent requests. A workaround is to both call set_header and set_persistent_header but I don't think that's on purpose
On Mon Oct 17 07:50:44 2016, ABRAXXA wrote: Show quoted text
> I'm using it against an API that requires a POST call against one > endpoint with basic auth to get an access-token which has to be > included in every API call from there on. > Setting the header using set_header works, but is only used for the > next request. Setting it using set_persistent_header doesn't use it > for the next but subsequent requests. > A workaround is to both call set_header and set_persistent_header but > I don't think that's on purpose
Thanks for the report. Would it be possible for you to devise a (failing) test to show the problem? That would help me a lot. /kaare
The problem seems to arise from the fact that the trigger method of persistent_headers isn't called. If I read https://metacpan.org/pod/MooX::HandlesVia#SHORTCOMINGS correctly that's a known shortcoming. I've added this test to t/rest.t: { ok(my $client = RESTExample->new({ server => 'http://localhost:3000', type => 'application/json', }), 'New object'); # if you uncomment one of those two lines the test fails #is($client->has_no_headers, 1, 'client has no headers'); #is_deeply($client->httpheaders, {}, 'client has no headers'); $client->set_persistent_header('X-Test' => 'foo' ); is_deeply($client->httpheaders, { 'X-Test' => 'foo' }, 'should have at least persistent_headers'); } In addition I've found that persistent_headers's trigger method doesn't get $old_header passed as per Moo's trigger docs. I suggest to remove trigger from persistent_headers, rename _build_httpheaders to a different internal method name which is then used whenever the headers are required. ETOOMUCHMAGIC currently.
I've attached a patch with one commit adding the failing test and one with a proposed fix which does fail one test in t/rest.t which is undefined behavior regarding the modules docs so you have to decide if it's worth to change what reset_headers does. You could also make it a sub that clears both httpheaders and persistent_headers, but that's not documented.
Subject: rt118413.patch
From 13c0b93c7cca4288f64064136f13ee6bedb1f4ea Mon Sep 17 00:00:00 2001 From: Alexander Hartmaier <abraxxa@cpan.org> Date: Mon, 24 Oct 2016 20:09:21 +0200 Subject: [PATCH 1/2] add failing test case for RT#118413 --- t/rest.t | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/t/rest.t b/t/rest.t index 4b4d166..dd16dcd 100644 --- a/t/rest.t +++ b/t/rest.t @@ -51,6 +51,18 @@ my %testdata = ( user_agent => $ua, persistent_headers => $persistent_headers, ); +{ + ok(my $client = RESTExample->new({ + server => 'http://localhost:3000', + type => 'application/json', + }), 'New object'); + is($client->has_no_headers, 1, 'client has no headers'); + #is_deeply($client->httpheaders, {}, 'client has no headers'); + $client->set_persistent_header('X-Test' => 'foo' ); + is_deeply($client->httpheaders, { 'X-Test' => 'foo' }, + 'should have at least persistent_headers'); + +} ok(my $obj = RESTExample->new(%testdata), 'New object'); isa_ok($obj, 'RESTExample'); -- 2.9.3 From 64564b870635d322ad1a48c13e324f66c1e46bd9 Mon Sep 17 00:00:00 2001 From: Alexander Hartmaier <abraxxa@cpan.org> Date: Mon, 24 Oct 2016 20:09:37 +0200 Subject: [PATCH 2/2] proposed patch for RT#118413 --- lib/Role/REST/Client.pm | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/Role/REST/Client.pm b/lib/Role/REST/Client.pm index 4d5faf7..f84d3c8 100644 --- a/lib/Role/REST/Client.pm +++ b/lib/Role/REST/Client.pm @@ -47,16 +47,9 @@ sub _build_user_agent { } has persistent_headers => ( - is => 'lazy', + is => 'rw', # isa => HashRef[Str], default => sub { {} }, - trigger => sub { - my ( $self, $header, $old_header ) = @_; - # Update httpheaders if their value was initialized first - while (my ($key, $value) = each %$header) { - $self->set_header($key, $value) unless $self->exist_header($key); - } - }, handles_via => 'Hash', handles => { set_persistent_header => 'set', @@ -66,10 +59,11 @@ has persistent_headers => ( }, ); -has httpheaders => ( - is => 'lazy', +has _httpheaders => ( + is => 'rw', isa => HashRef[Str], - writer => '_set_httpheaders', + init_arg => 'httpheaders', + default => sub { {} }, handles_via => 'Hash', handles => { set_header => 'set', @@ -77,9 +71,15 @@ has httpheaders => ( exist_header => 'exists', has_no_headers => 'is_empty', clear_headers => 'clear', + reset_headers => 'clear', }, ); +sub httpheaders { + my $self = shift; + return { %{$self->persistent_headers}, %{$self->_httpheaders} }; +} + has serializer_class => ( isa => Str, is => 'ro', @@ -92,14 +92,6 @@ has serializer_options => ( default => sub { return {} }, ); -sub _build_httpheaders { - my ($self, $headers) = @_; - $headers ||= {}; - $self->_set_httpheaders( { %{$self->persistent_headers}, %$headers }); -} - -sub reset_headers {my $self = shift;$self->_set_httpheaders({ %{$self->persistent_headers} })} - sub _rest_response_class { 'Role::REST::Client::Response' } # If the response is a hashref, we expect it to be in the format returned by -- 2.9.3
Added a clear_all_headers method
I can confirm that it's working now, thanks!