[Bps-public-commit] rt-extension-rest2 branch, master, updated. c8581fb576e41372f0d4e6a4ec8827ed8c142f6b
Shawn Moore
shawn at bestpractical.com
Tue Dec 13 14:08:41 EST 2016
The branch, master has been updated
via c8581fb576e41372f0d4e6a4ec8827ed8c142f6b (commit)
via 0d514b49bcdf5d86d3f54e36fb57fd5749deaba0 (commit)
via 607b65fc5717e3447eeef7e7f7ab01f519bc99ed (commit)
via 9d094915573ac83c2ca8f17e91fde46c7f9d86b2 (commit)
via a5b5d60aa2a03288e2670010ed9a705c942461cb (commit)
from 37d8be7cf9551eef657232e55099c6112ffd8006 (commit)
Summary of changes:
README | 8 ++--
lib/RT/Extension/REST2.pm | 8 ++--
lib/RT/Extension/REST2/Resource/Record.pm | 11 ++++--
lib/RT/Extension/REST2/Resource/Record/Writable.pm | 8 ++--
.../REST2/Resource/Role/RequestBodyIsJSON.pm | 2 +-
t/lib/RT/Extension/REST2/Test.pm.in | 44 +++++++++++++++++++---
t/not_found.t | 6 +--
t/root.t | 10 +----
t/tickets.t | 29 +++++++-------
9 files changed, 77 insertions(+), 49 deletions(-)
- Log -----------------------------------------------------------------
commit a5b5d60aa2a03288e2670010ed9a705c942461cb
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Dec 13 18:11:37 2016 +0000
Replace TODO comment with TODO test
diff --git a/t/tickets.t b/t/tickets.t
index 7519af1..7bd6750 100644
--- a/t/tickets.t
+++ b/t/tickets.t
@@ -55,8 +55,10 @@ my ($ticket_url, $ticket_id);
'Content-Type' => 'application/json; charset=utf-8',
'Authorization' => $auth,
);
- # TODO: This should return 403
- is($res->code, 400);
+ TODO: {
+ local $TODO = "this should return 403";
+ is($res->code, 403);
+ }
# Rights Test - With CreateTicket
$user->PrincipalObj->GrantRight( Right => 'CreateTicket' );
commit 9d094915573ac83c2ca8f17e91fde46c7f9d86b2
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Dec 13 18:15:28 2016 +0000
Test the ticket search result content
diff --git a/t/tickets.t b/t/tickets.t
index 7bd6750..2bb83f3 100644
--- a/t/tickets.t
+++ b/t/tickets.t
@@ -137,6 +137,11 @@ my ($ticket_url, $ticket_id);
is($content->{per_page}, 20);
is($content->{total}, 1);
is(scalar @{$content->{items}}, 1);
+
+ my $ticket = $content->{items}->[0];
+ is($ticket->{type}, 'ticket');
+ is($ticket->{id}, 1);
+ like($ticket->{_url}, qr{$rest_base_path/ticket/1$});
}
done_testing;
commit 607b65fc5717e3447eeef7e7f7ab01f519bc99ed
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Dec 13 18:49:05 2016 +0000
Subclass Test::WWW::Mechanize::PSGI
diff --git a/t/lib/RT/Extension/REST2/Test.pm.in b/t/lib/RT/Extension/REST2/Test.pm.in
index 08c5f99..a060375 100644
--- a/t/lib/RT/Extension/REST2/Test.pm.in
+++ b/t/lib/RT/Extension/REST2/Test.pm.in
@@ -12,11 +12,7 @@ use RT::Extension::REST2;
use Test::WWW::Mechanize::PSGI;
use RT::User;
-sub mech {
- my $mech = Test::WWW::Mechanize::PSGI->new(
- app => RT::Extension::REST2->to_app,
- );
-}
+sub mech { RT::Extension::REST2::Test::Mechanize->new }
{
my $u;
@@ -42,4 +38,18 @@ sub mech {
}
}
+{
+ package RT::Extension::REST2::Test::Mechanize;
+ use parent 'Test::WWW::Mechanize::PSGI';
+
+ sub new {
+ my $class = shift;
+ my %args = (
+ app => RT::Extension::REST2->to_app,
+ @_,
+ );
+ return $class->SUPER::new(%args);
+ }
+}
+
1;
commit 0d514b49bcdf5d86d3f54e36fb57fd5749deaba0
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Dec 13 18:50:32 2016 +0000
Simplify the common case of processing JSON responses
diff --git a/t/lib/RT/Extension/REST2/Test.pm.in b/t/lib/RT/Extension/REST2/Test.pm.in
index a060375..771e3c9 100644
--- a/t/lib/RT/Extension/REST2/Test.pm.in
+++ b/t/lib/RT/Extension/REST2/Test.pm.in
@@ -42,6 +42,9 @@ sub mech { RT::Extension::REST2::Test::Mechanize->new }
package RT::Extension::REST2::Test::Mechanize;
use parent 'Test::WWW::Mechanize::PSGI';
+ use JSON;
+ my $json = JSON->new->utf8;
+
sub new {
my $class = shift;
my %args = (
@@ -50,6 +53,19 @@ sub mech { RT::Extension::REST2::Test::Mechanize->new }
);
return $class->SUPER::new(%args);
}
+
+ sub json_response {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my $self = shift;
+
+ my $res = $self->response;
+
+ local $main::TODO;
+ Test::More::like($res->header('content-type'),
+ qr{^application/json(?:; charset="?utf-8"?)?$});
+
+ return $json->decode($res->content);
+ }
}
1;
diff --git a/t/not_found.t b/t/not_found.t
index a152b2d..9a68f56 100644
--- a/t/not_found.t
+++ b/t/not_found.t
@@ -2,20 +2,16 @@ use strict;
use warnings;
use lib 't/lib';
use RT::Extension::REST2::Test tests => undef;
-use JSON;
my $mech = RT::Extension::REST2::Test->mech;
my $auth = RT::Extension::REST2::Test->authorization_header;
my $rest_base_path = '/REST/2.0';
-my $json = JSON->new->utf8;
sub is_404 {
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $res = shift;
is($res->code, 404);
- is($res->header('content-type'), 'application/json; charset=utf-8');
- my $content = $json->decode($res->content);
- is($content->{message}, 'Not Found');
+ is($mech->json_response->{message}, 'Not Found');
}
# Proper 404 Response
diff --git a/t/root.t b/t/root.t
index 214f366..ebb43fe 100644
--- a/t/root.t
+++ b/t/root.t
@@ -2,21 +2,17 @@ use strict;
use warnings;
use lib 't/lib';
use RT::Extension::REST2::Test tests => undef;
-use JSON;
my $mech = RT::Extension::REST2::Test->mech;
my $rest_base_path = '/REST/2.0';
-my $json = JSON->new->utf8;
# Unauthorized without Basic Auth
{
my $res = $mech->get($rest_base_path);
is($res->code, 401, 'Unauthorized');
- is($res->header('content-type'), 'application/json; charset=utf-8');
is($res->header('www-authenticate'), 'Basic realm="example.com REST API"');
- my $content = $json->decode($res->content);
- is($content->{message}, 'Unauthorized');
+ is($mech->json_response->{message}, 'Unauthorized');
}
my $auth = RT::Extension::REST2::Test->authorization_header;
@@ -50,9 +46,7 @@ my $auth = RT::Extension::REST2::Test->authorization_header;
);
is($res->code, 405);
is($res->header('allow'), 'GET,HEAD,OPTIONS');
- is($res->header('content-type'), 'application/json; charset=utf-8');
- my $content = $json->decode($res->content);
- is($content->{message}, 'Method Not Allowed');
+ is($mech->json_response->{message}, 'Method Not Allowed');
}
done_testing;
diff --git a/t/tickets.t b/t/tickets.t
index 2bb83f3..8ced0c7 100644
--- a/t/tickets.t
+++ b/t/tickets.t
@@ -2,7 +2,6 @@ use strict;
use warnings;
use lib 't/lib';
use RT::Extension::REST2::Test tests => undef;
-use JSON;
my $mech = RT::Extension::REST2::Test->mech;
@@ -16,9 +15,8 @@ my $user = RT::Extension::REST2::Test->user;
my $res = $mech->get("$rest_base_path/tickets?query=id>0",
'Authorization' => $auth,
);
- is($res->header('content-type'), 'application/json; charset="utf-8"');
- my $content = $json->decode($res->content);
- is($content->{count}, 0);
+ is($res->code, 200);
+ is($mech->json_response->{count}, 0);
}
# Missing Queue
@@ -33,9 +31,7 @@ my $user = RT::Extension::REST2::Test->user;
'Authorization' => $auth,
);
is($res->code, 400);
- is($res->header('content-type'), 'application/json; charset=utf-8');
- my $content = $json->decode($res->content);
- is($content->{message}, 'Could not create ticket. Queue not set');
+ is($mech->json_response->{message}, 'Could not create ticket. Queue not set');
}
# Ticket Creation
@@ -68,8 +64,6 @@ my ($ticket_url, $ticket_id);
'Authorization' => $auth,
);
is($res->code, 201);
-
- is($res->header('content-type'), 'application/json; charset="utf-8"');
ok($ticket_url = $res->header('location'));
ok($ticket_id = $ticket_url =~ qr[/ticket/(\d+)]);
}
@@ -92,8 +86,7 @@ my ($ticket_url, $ticket_id);
);
is($res->code, 200);
- is($res->header('content-type'), 'application/json; charset="utf-8"');
- my $content = $json->decode($res->content);
+ my $content = $mech->json_response;
is($content->{id}, $ticket_id);
is($content->{Type}, 'ticket');
is($content->{Status}, 'new');
@@ -130,8 +123,7 @@ my ($ticket_url, $ticket_id);
'Authorization' => $auth,
);
is($res->code, 200);
- is($res->header('content-type'), 'application/json; charset="utf-8"');
- my $content = $json->decode($res->content);
+ my $content = $mech->json_response;
is($content->{count}, 1);
is($content->{page}, 1);
is($content->{per_page}, 20);
commit c8581fb576e41372f0d4e6a4ec8827ed8c142f6b
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Dec 13 18:22:17 2016 +0000
Replace PUT with PATCH
PUT is meant to specify a complete replacement in the content; PATCH is
for specifying partial modifications. Since RT's Update() routines take
partial modifications and not complete replacements, PATCH is the more
correct method.
https://tools.ietf.org/html/rfc5789
"The difference between the PUT and PATCH requests is reflected in the
way the server processes the enclosed entity to modify the resource
identified by the Request-URI. In a PUT request, the enclosed entity is
considered to be a modified version of the resource stored on the origin
server, and the client is requesting that the stored version be
replaced. With PATCH, however, the enclosed entity contains a set of
instructions describing how a resource currently residing on the origin
server should be modified to produce a new version."
diff --git a/README b/README
index e12bb05..2ba9d30 100644
--- a/README
+++ b/README
@@ -22,17 +22,17 @@ USAGE
Currently provided endpoints under /REST/2.0/ are:
GET /ticket/:id
- PUT /ticket/:id <JSON body>
+ PATCH /ticket/:id <JSON body>
DELETE /ticket/:id
Sets ticket status to "deleted".
GET /queue/:id
- PUT /queue/:id <JSON body>
+ PATCH /queue/:id <JSON body>
DELETE /queue/:id
Disables the queue.
GET /user/:id
- PUT /user/:id <JSON body>
+ PATCH /user/:id <JSON body>
DELETE /user/:id
Disables the user.
@@ -41,7 +41,7 @@ USAGE
When a GET request is made, each endpoint returns a JSON representation
of the specified resource, or a 404 if not found.
- When a PUT request is made, the request body should be a modified copy
+ When a PATCH request is made, the request body should be a modified copy
(or partial copy) of the JSON representation of the specified resource,
and the record will be updated.
diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index a3d6591..0a7090c 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -50,17 +50,17 @@ Add this line:
Currently provided endpoints under C</REST/2.0/> are:
GET /ticket/:id
- PUT /ticket/:id <JSON body>
+ PATCH /ticket/:id <JSON body>
DELETE /ticket/:id
Sets ticket status to "deleted".
GET /queue/:id
- PUT /queue/:id <JSON body>
+ PATCH /queue/:id <JSON body>
DELETE /queue/:id
Disables the queue.
GET /user/:id
- PUT /user/:id <JSON body>
+ PATCH /user/:id <JSON body>
DELETE /user/:id
Disables the user.
@@ -69,7 +69,7 @@ For queues and users, C<:id> may be the numeric id or the unique name.
When a GET request is made, each endpoint returns a JSON representation of the
specified resource, or a 404 if not found.
-When a PUT request is made, the request body should be a modified copy (or
+When a PATCH request is made, the request body should be a modified copy (or
partial copy) of the JSON representation of the specified resource, and the
record will be updated.
diff --git a/lib/RT/Extension/REST2/Resource/Record.pm b/lib/RT/Extension/REST2/Resource/Record.pm
index 99d7935..9a7e34c 100644
--- a/lib/RT/Extension/REST2/Resource/Record.pm
+++ b/lib/RT/Extension/REST2/Resource/Record.pm
@@ -68,12 +68,17 @@ sub last_modified {
return create_date($updated);
}
+sub known_methods {
+ my $self = shift;
+ return [@{$self->SUPER::known_methods(@_)}, 'PATCH'];
+}
+
sub allowed_methods {
my $self = shift;
my @ok;
- push @ok, 'GET', 'HEAD' if $self->DOES("RT::Extension::REST2::Resource::Record::Readable");
- push @ok, 'DELETE' if $self->DOES("RT::Extension::REST2::Resource::Record::Deletable");
- push @ok, 'PUT', 'POST' if $self->DOES("RT::Extension::REST2::Resource::Record::Writable");
+ push @ok, 'GET', 'HEAD' if $self->DOES("RT::Extension::REST2::Resource::Record::Readable");
+ push @ok, 'DELETE' if $self->DOES("RT::Extension::REST2::Resource::Record::Deletable");
+ push @ok, 'PATCH', 'POST' if $self->DOES("RT::Extension::REST2::Resource::Record::Writable");
return \@ok;
}
diff --git a/lib/RT/Extension/REST2/Resource/Record/Writable.pm b/lib/RT/Extension/REST2/Resource/Record/Writable.pm
index 65b5d57..048af88 100644
--- a/lib/RT/Extension/REST2/Resource/Record/Writable.pm
+++ b/lib/RT/Extension/REST2/Resource/Record/Writable.pm
@@ -30,9 +30,9 @@ sub from_json {
);
my $method = $self->request->method;
- return $method eq 'PUT' ? $self->update_resource($data) :
- $method eq 'POST' ? $self->create_resource($data) :
- \501 ;
+ return $method eq 'PATCH' ? $self->update_resource($data) :
+ $method eq 'POST' ? $self->create_resource($data) :
+ \501 ;
}
sub update_resource {
@@ -69,7 +69,7 @@ sub create_resource {
if ($self->resource_exists) {
return error_as_json(
$self->response,
- \409, "Resource already exists; use PUT to update");
+ \409, "Resource already exists; use PATCH to update");
}
my ($ok, $msg) = $self->create_record($data);
diff --git a/lib/RT/Extension/REST2/Resource/Role/RequestBodyIsJSON.pm b/lib/RT/Extension/REST2/Resource/Role/RequestBodyIsJSON.pm
index 2d571cc..dbe38ec 100644
--- a/lib/RT/Extension/REST2/Resource/Role/RequestBodyIsJSON.pm
+++ b/lib/RT/Extension/REST2/Resource/Role/RequestBodyIsJSON.pm
@@ -24,7 +24,7 @@ role {
return $malformed if $malformed;
my $request = $self->request;
- return 0 unless $request->method =~ /^(PUT|POST)$/;
+ return 0 unless $request->method =~ /^(PUT|POST|PATCH)$/;
my $json = eval {
JSON::from_json($request->content)
diff --git a/t/lib/RT/Extension/REST2/Test.pm.in b/t/lib/RT/Extension/REST2/Test.pm.in
index 771e3c9..be15105 100644
--- a/t/lib/RT/Extension/REST2/Test.pm.in
+++ b/t/lib/RT/Extension/REST2/Test.pm.in
@@ -66,6 +66,14 @@ sub mech { RT::Extension::REST2::Test::Mechanize->new }
return $json->decode($res->content);
}
+
+ # modeled off of LWP::UserAgent::put
+ sub patch {
+ require HTTP::Request::Common;
+ my($self, @parameters) = @_;
+ my @suff = $self->_process_colonic_headers(\@parameters, (ref($parameters[1]) ? 2 : 1));
+ return $self->request( HTTP::Request::Common::_simple_req( 'PATCH', @parameters ), @suff );
+ }
}
1;
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list