From: adam Date: Sun, 3 Dec 2006 23:56:15 +0000 (+0000) Subject: r53@latte: adam | 2006-12-03 16:00:44 -0800 X-Git-Tag: 1.08~282 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=8f00a41bd7efb75d302d0a333e0eb5bc7d75c931;p=catagits%2FCatalyst-Action-Serialize-Data-Serializer.git r53@latte: adam | 2006-12-03 16:00:44 -0800 Renamed some test files, since we don't care about order. Updated for an 0.30 release Deleted the SampleREST test app, since it's been greatly simplified. Updated the README --- diff --git a/Changelog b/Changelog index 14957b9..9252865 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,8 @@ -Sun Dec 3 12:24:16 PST 2006 (adam) +Sun Dec 3 12:24:16 PST 2006 (adam) - Release 0.30 + Updated the Makefile to support optional installation of the different + Serialization formats. + Renamed some of the test cases, since the execution order doesn't + matter. Fixed things so that not having a Serialization module returns 415. Fixed things so that failure to Deserialize sends the proper status. Refactored the Plugin loading to Catalyst::Action::SerializeBase. diff --git a/Makefile.PL b/Makefile.PL index a1e14ab..e1048f5 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -12,6 +12,31 @@ requires('Module::Pluggable::Object' => undef); requires('LWP::UserAgent' => '2.033'); requires('Data::Serializer' => '0.36'); requires('Class::Inspector' => '1.13'); +requires('URI::Find' => undef); + +feature 'Data::Denter (text/x-data-denter) support', + -default => 0, + 'Data::Denter' => undef; + +feature 'Data::Taxi (text/x-data-taxi) support', + -default => 0, + 'Data::Taxi' => undef; + +feature 'Config::General (text/x-config-general) support', + -default => 0, + 'Config::General' => undef; + +feature 'PHP::Serialization (text/x-php-serialization) support', + -default => 0, + 'PHP::Serialization' => undef; + +feature 'FreezeThaw (application/x-freezethaw) support', + -default => 0, + 'FreezeThaw' => undef; + +feature 'XML::Simple (text/xml) support', + -default => 0, + 'XML::Simple' => undef; auto_include; auto_install; diff --git a/README b/README index f7175e2..8da598b 100644 --- a/README +++ b/README @@ -43,39 +43,124 @@ DESCRIPTION thing will be dispatched to "thing_GET", while any PUT requests will be dispatched to "thing_PUT". - Any unimplemented HTTP METHODS will be met with a "405 Method Not + Any unimplemented HTTP methods will be met with a "405 Method Not Allowed" response, automatically containing the proper list of available - methods. + methods. You can override this behavior through implementing a custom + "thing_not_implemented" method. + + If you do not provide an OPTIONS handler, we will respond to any OPTIONS + requests with a "200 OK", populating the Allowed header automatically. + + Any data included in "$c->stash->{'rest'}" will be serialized for you. + The serialization format will be selected based on the content-type of + the incoming request. It is probably easier to use the "STATUS HELPERS", + which are described below. The HTTP POST, PUT, and OPTIONS methods will all automatically deserialize the contents of $c->request->body based on the requests content-type header. A list of understood serialization formats is below. - Also included in this class are several helper methods, which will - automatically handle setting up proper response objects for you. + If we do not have (or cannot run) a serializer for a given content-type, + a 415 "Unsupported Media Type" error is generated. To make your Controller RESTful, simply have it use base 'Catalyst::Controller::REST'; SERIALIZATION - Catalyst::Controller::REST will automatically serialize your responses. - The currently implemented serialization formats are: + Catalyst::Controller::REST will automatically serialize your responses, + and deserialize any POST, PUT or OPTIONS requests. It evaluates which + serializer to use by mapping a content-type to a Serialization module. + We select the content-type based on: + + The Content-Type Header + If the incoming HTTP Request had a Content-Type header set, we will + use it. + + The content-type Query Parameter + If this is a GET request, you can supply a content-type query + parameter. + + Evaluating the Accept Header + Finally, if the client provided an Accept header, we will evaluate it + and use the best-ranked choice. + +AVAILABLE SERIALIZERS + A given serialization mechanism is only available if you have the + underlying modules installed. For example, you can't use XML::Simple if + it's not already installed. + + In addition, each serializer has it's quirks in terms of what sorts of + data structures it will properly handle. Catalyst::Controller::REST + makes no attempt to svae you from yourself in this regard. :) + + "text/x-yaml" => "YAML::Syck" + Returns YAML generated by YAML::Syck. + + "text/html" => "YAML::HTML" + This uses YAML::Syck and URI::Find to generate YAML with all URLs + turned to hyperlinks. Only useable for Serialization. + + "text/x-json" => "JSON::Syck" + Uses JSON::Syck to generate JSON output + + "text/x-data-dumper" => "Data::Serializer" + Uses the Data::Serializer module to generate Data::Dumper output. + + "text/x-data-denter" => "Data::Serializer" + Uses the Data::Serializer module to generate Data::Denter output. + + "text/x-data-taxi" => "Data::Serializer" + Uses the Data::Serializer module to generate Data::Taxi output. + + "application/x-storable" => "Data::Serializer" + Uses the Data::Serializer module to generate Storable output. + + "application/x-freezethaw" => "Data::Serializer" + Uses the Data::Serializer module to generate FreezeThaw output. - text/x-yaml -> YAML::Syck - text/x-data-dumper -> Data::Serializer + "text/x-config-general" => "Data::Serializer" + Uses the Data::Serializer module to generate Config::General output. - By default, Catalyst::Controller::REST will use YAML as the - serialization format. + "text/x-php-serialization" => "Data::Serializer" + Uses the Data::Serializer module to generate PHP::Serialization + output. + + "text/xml" => "XML::Simple" + Uses XML::Simple to generate XML output. This is probably not suitable + for any real heavy XML work. Due to XML::Simples requirement that the + data you serialize be a HASHREF, we transform outgoing data to be in + the form of: + + { data => $yourdata } + + By default, Catalyst::Controller::REST will return a "415 Unsupported + Media Type" response if an attempt to use an unsupported content-type is + made. You can ensure that something is always returned by setting the + "default" config option: + + __PACKAGE__->config->{'serialize'}->{'default'} = 'YAML'; + + Would make it always fall back to YAML. Implementing new Serialization formats is easy! Contributions are most welcome! See Catalyst::Action::Serialize and Catalyst::Action::Deserialize for more information. +CUSTOM SERIALIZERS + If you would like to implement a custom serializer, you should create + two new modules in the Catalyst::Action::Serialize and + Catalyst::Action::Deserialize namespace. Then assign your new class to + the content-type's you want, and you're done. + STATUS HELPERS + Since so much of REST is in using HTTP, we provide these Status Helpers. + Using them will ensure that you are responding with the proper codes, + headers, and entities. + These helpers try and conform to the HTTP 1.1 Specification. You can - refer to it at: http://www.w3.org/Protocols/rfc2616/rfc2616.txt. These + refer to it at: . These routines are all implemented as regular subroutines, and as such require you pass the current context ($c) as the first argument. @@ -129,9 +214,7 @@ STATUS HELPERS $self->status_bad_request( $c, - entity => { - message => "Cannot do what you have asked!", - } + message => "Cannot do what you have asked!", ); status_not_found @@ -143,35 +226,98 @@ STATUS HELPERS $self->status_not_found( $c, - entity => { - message => "Cannot find what you were looking for!", - } + message => "Cannot find what you were looking for!", ); MANUAL RESPONSES If you want to construct your responses yourself, all you need to do is put the object you want serialized in $c->stash->{'rest'}. +IMPLEMENTATION DETAILS + This Controller ties together Catalyst::Action::REST, + Catalyst::Action::Serialize and Catalyst::Action::Deserialize. It should + be suitable for most applications. You should be aware that it: + + Configures the Serialization Actions + This class provides a default configuration for Serialization. It is + currently: + + __PACKAGE__->config( + serialize => { + 'stash_key' => 'rest', + 'map' => { + 'text/html' => 'YAML::HTML', + 'text/xml' => 'XML::Simple', + 'text/x-yaml' => 'YAML', + 'text/x-json' => 'JSON', + 'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ], + 'text/x-data-denter' => [ 'Data::Serializer', 'Data::Denter' ], + 'text/x-data-taxi' => [ 'Data::Serializer', 'Data::Taxi' ], + 'application/x-storable' => [ 'Data::Serializer', 'Storable' + ], + 'application/x-freezethaw' => [ 'Data::Serializer', 'FreezeThaw' + ], + 'text/x-config-general' => [ 'Data::Serializer', 'Config::General' ] + , + 'text/x-php-serialization' => [ 'Data::Serializer', 'PHP::Serializat + ion' ], + }, + } + ); + + You can read the full set of options for this configuration block in + Catalyst::Action::Serialize. + + Sets a "begin" and "end" method for you + The "begin" method uses Catalyst::Action::Deserialize. The "end" + method uses Catalyst::Action::Serialize. If you want to override + either behavior, simply implement your own "begin" and "end" actions + and use NEXT: + + my Foo::Controller::Monkey; + use base qw(Catalyst::Controller::REST); + + sub begin :Private { + my ($self, $c) = @_; + ... do things before Deserializing ... + $self->NEXT::begin($c); + ... do things after Deserializing ... + } + + sub end :Private { + my ($self, $c) = @_; + ... do things before Serializing ... + $self->NEXT::end($c); + ... do things after Serializing ... + } + +A MILD WARNING + I have code in production using Catalyst::Controller::REST. That + said, it is still under development, and it's possible that things + may change between releases. I promise to not break things + unneccesarily. :) + SEE ALSO - Catalyst::Action::REST, Catalyst::Action::Serialize, - Catalyst::Action::Deserialize + Catalyst::Action::REST, Catalyst::Action::Serialize, + Catalyst::Action::Deserialize - For help with REST in general: + For help with REST in general: - The HTTP 1.1 Spec is required reading. - http://www.w3.org/Protocols/rfc2616/rfc2616.txt + The HTTP 1.1 Spec is required reading. + http://www.w3.org/Protocols/rfc2616/rfc2616.txt - Wikipedia! http://en.wikipedia.org/wiki/Representational_State_Transfer + Wikipedia! + http://en.wikipedia.org/wiki/Representational_State_Transfer - The REST Wiki: http://rest.blueoxen.net/cgi-bin/wiki.pl?FrontPage + The REST Wiki: http://rest.blueoxen.net/cgi-bin/wiki.pl?FrontPage AUTHOR - Adam Jacob , with lots of help from mst and - jrockway + Adam Jacob , with lots of help from mst and + jrockway - Marchex, Inc. paid me while I developed this module. - (http://www.marchex.com) + Marchex, Inc. paid me while I developed this module. + (http://www.marchex.com) LICENSE - You may distribute this code under the same terms as Perl itself. + You may distribute this code under the same terms as Perl itself. diff --git a/lib/Catalyst/Action/REST.pm b/lib/Catalyst/Action/REST.pm index 9411ac2..0bd3fb7 100644 --- a/lib/Catalyst/Action/REST.pm +++ b/lib/Catalyst/Action/REST.pm @@ -15,7 +15,7 @@ use Class::Inspector; use 5.8.1; our -$VERSION = '0.2'; +$VERSION = '0.30'; =head1 NAME diff --git a/t/02-data-serializer.t b/t/data-serializer.t similarity index 100% rename from t/02-data-serializer.t rename to t/data-serializer.t diff --git a/t/02-json.t b/t/json.t similarity index 100% rename from t/02-json.t rename to t/json.t diff --git a/t/lib/SampleREST.pm b/t/lib/SampleREST.pm deleted file mode 100644 index 0a9dcee..0000000 --- a/t/lib/SampleREST.pm +++ /dev/null @@ -1,62 +0,0 @@ -package SampleREST; - -use strict; -use warnings; - -use Catalyst::Runtime '5.70'; - -# Set flags and add plugins for the application -# -# -Debug: activates the debug mode for very useful log messages -# ConfigLoader: will load the configuration from a YAML file in the -# application's home directory -# Static::Simple: will serve static files from the application's root -# directory - -use Catalyst qw/ConfigLoader/; - -our $VERSION = '0.01'; - -# Configure the application. -# -# Note that settings in SampleREST.yml (or other external -# configuration file that you set up manually) take precedence -# over this when using ConfigLoader. Thus configuration -# details given here can function as a default configuration, -# with a external configuration file acting as an override for -# local deployment. - -__PACKAGE__->config( name => 'SampleREST' ); - -# Start the application -__PACKAGE__->setup; - - -=head1 NAME - -SampleREST - Catalyst based application - -=head1 SYNOPSIS - - script/samplerest_server.pl - -=head1 DESCRIPTION - -[enter your description here] - -=head1 SEE ALSO - -L, L - -=head1 AUTHOR - -Adam Jacob - -=head1 LICENSE - -This library is free software, you can redistribute it and/or modify -it under the same terms as Perl itself. - -=cut - -1; diff --git a/t/lib/SampleREST/Controller/Monkey.pm b/t/lib/SampleREST/Controller/Monkey.pm deleted file mode 100644 index 9adc994..0000000 --- a/t/lib/SampleREST/Controller/Monkey.pm +++ /dev/null @@ -1,23 +0,0 @@ -package SampleREST::Controller::Monkey; - -use strict; -use warnings; -use base 'Catalyst::Controller::REST'; - -sub myindex :Path :Args(0) :ActionClass('REST') {} - -sub myindex_GET { - my ( $self, $c, $rdata ) = @_; - - $c->stash->{'rest'} = { - 'monkey' => 'likes chicken!', - }; -} - -sub myindex_POST { - my ( $self, $c, $rdata ) = @_; - - $c->stash->{'rest'} = $c->request->data; -} - -1; diff --git a/t/lib/SampleREST/Controller/Root.pm b/t/lib/SampleREST/Controller/Root.pm deleted file mode 100644 index 72a9ce9..0000000 --- a/t/lib/SampleREST/Controller/Root.pm +++ /dev/null @@ -1,55 +0,0 @@ -package SampleREST::Controller::Root; - -use strict; -use warnings; -use base 'Catalyst::Controller'; - -# -# Sets the actions in this controller to be registered with no prefix -# so they function identically to actions created in MyApp.pm -# -__PACKAGE__->config->{namespace} = ''; - -=head1 NAME - -SampleREST::Controller::Root - Root Controller for SampleREST - -=head1 DESCRIPTION - -[enter your description here] - -=head1 METHODS - -=cut - -=head2 default - -=cut - -sub default : Private { - my ( $self, $c ) = @_; - - # Hello World - $c->response->body( $c->welcome_message ); -} - -=head2 end - -Attempt to render a view, if needed. - -=cut - -sub end : ActionClass('RenderView') {} - -=head1 AUTHOR - -Adam Jacob - -=head1 LICENSE - -This library is free software, you can redistribute it and/or modify -it under the same terms as Perl itself. - -=cut - -1; diff --git a/t/02-xml-simple.t b/t/xml-simple.t similarity index 100% rename from t/02-xml-simple.t rename to t/xml-simple.t diff --git a/t/02-yaml-html.t b/t/yaml-html.t similarity index 100% rename from t/02-yaml-html.t rename to t/yaml-html.t diff --git a/t/02-yaml.t b/t/yaml.t similarity index 100% rename from t/02-yaml.t rename to t/yaml.t