Mercurial > pub > Impl
diff Lib/IMPL/Web/Application/RestResource.pm @ 197:6b1dda998839
Added IMPL::declare, IMPL::require, to simplify module definitions
IMPL::Transform now admires object inheritance while searching for the transformation
Added HTTP some exceptions
IMPL::Web::Application::RestResource almost implemented
author | sergey |
---|---|
date | Thu, 19 Apr 2012 02:10:02 +0400 |
parents | a705e848dcc7 |
children | 2ffe6f661605 |
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/RestResource.pm Mon Apr 16 17:42:54 2012 +0400 +++ b/Lib/IMPL/Web/Application/RestResource.pm Thu Apr 19 02:10:02 2012 +0400 @@ -1,6 +1,139 @@ package IMPL::Web::Application::RestResource; use strict; +use IMPL::lang qw(:declare :constants); +use IMPL::declare { + require => { + ForbiddenException => 'IMPL::Web::ForbiddenException' + }, + base => { + 'IMPL::Object' => undef + } +}; + +BEGIN { + public property target => PROP_GET | PROP_OWNERSET; + public property methods => PROP_GET | PROP_OWNERSET; + public property childRegex => PROP_GET | PROP_OWNERSET; + public property list => PROP_GET | PROP_OWNERSET; + public property fetch => PROP_GET | PROP_OWNERSET; + public property insert => PROP_GET | PROP_OWNERSET; + public property update => PROP_GET | PROP_OWNERSET; + public property delete => PROP_GET | PROP_OWNERSET; +} + +sub GetHttpImpl { + my($this,$method) = @_; + + my %map = ( + GET => 'GetImpl', + PUT => 'PutImpl', + POST => 'PostImpl', + DELETE => 'DeleteImpl' + ); + + return $map{$method}; +} + +sub InvokeHttpMethod { + my ($this,$method,$child,$action) = @_; + + my $impl = $this->GetHttpImpl($method) || 'FallbackImpl'; + + return $this->$impl($child,$action); +} + +sub GetImpl { + my ($this,$id,$action) = @_; + + my $rx; + my $method; + if (length $id == 0) { + $method = $this->list; + } elsif ($method = $this->methods->{$id}) { + if (ref $method eq 'HASH' and not $method->{allowGet}) { + die ForbiddenException->new(); + } + } elsif($rx = $this->childRegex and $id =~ m/$rx/ ) { + $method = $this->fetch or die ForbiddenException->new(); + + $method = { + method => $method, + parameters => [qw(id)] + } unless ref $method; + + } else { + die ForbiddenException->new(); + } + + return $this->InvokeMember($method,$id,$action); +} + +sub PutImpl { + my ($this,$id,$action) = @_; + + my $rx = $this->childRegex; + if ( $rx and $id =~ m/$rx/ and $this->update ) { + my $method = $this->update or die ForbiddenException->new(); + + $method = { + method => $method, + parameters => [qw(id query)] + } unless ref $method; + + return $this->InvokeMember($method,$id,$action); + } else { + die ForbiddenException->new(); + } +} + +sub PostImpl { + my ($this,$id,$action) = @_; + + my $method; + + if (length $id == 0) { + $method = $this->insert or die ForbiddenException->new(); + + $method = { + method => $method, + parameters => [qw(query)] + } unless ref $method; + } elsif ($method = $this->methods->{$id}) { + die ForbiddenException->new() unless ref $method and $method->{allowPost}; + } else { + die ForbiddenException->new(); + } + + return $this->InvokeMemeber($method,$id,$action); +} + +sub DeleteImpl { + my ($this,$id,$action) = @_; + + my $rx = $this->childRegex; + if ($rx and $id =~ m/$rx/ and my $method = $this->delete) { + + $method = { + method => $method, + parameters => [qw(id)] + } unless ref $method; + + return $this->InvokeMember($method,$id,$action); + } else { + die ForbiddenException->new(); + } +} + +sub HttpFallbackImpl { + die ForbiddenException->new(); +} + +sub InvokeMember { + my ($this,$method,$id,$action) = @_; +} + + 1; __END__ @@ -11,6 +144,138 @@ C<IMPL::Web::Application::RestResource> - ресурс Rest вебсервиса. +=head1 SYNOPSIS + +=begin text + +[REQUEST] +GET /artists + +[RESPONSE] +<artists> + <artist id="1"> + <name>The Beatles <name/> + </atrist> + <artist id="2"> + <name>Bonobo</name> + </artist> +</artists> + +[REQUEST] +GET /artists/1/cds?title='Live at BBC' + +[RESPONSE] +<cds> + <cd id="14"> + <title>Live at BBC 1</title> + </cd> + <cd id="15"> + <title>Live at BBC 2</title> + </cd> +</cds> + +[REQUEST] +GET /cds/15 + +[RESPONSE] +<cd id="15"> + <title>Live at BBC 2</title> +</cd> + +=end text + +=begin code + +use IMPL::require { + TRes => 'IMPL::Web:Application::RestResource', + DataContext => 'My::App::DataContext' +}; + +my $cds = TRes->new( + DataContext->Default, + { + methods => { + get => { + + }, + post => { + + } + } + get => 'search', + + + } +); + +=end code + =head1 DESCRIPTION +Каждый ресурс представляет собой коллекцию и реализует методы C<HTTP> C<GET,POST,PUT,DELETE>. + +=head2 HTTP METHODS + +=head3 C<GET> + +Возвращает коллекцию дочерних ресурсов. + +=head3 C<GET {id}> + +Возвращает дочерний объект с идентификатором C<id> + +=head3 C<GET {method}> + +Вызывает метод C<method> и возвращает его результаты. При публикации методов доступных +через C<GET> данные методы не должны вносить изменений в предметную область. + +=head3 C<PUT {id}> + +Обновляет дочерний ресурс с указанным идентификатором. + +=head3 C<DELETE {id}> + +Удаляет дочерний ресурс с указанным идентификатором. + +=head3 C<POST> + +Добавляет новый дочерний ресурс в коллекцию. + +=head2 HTTP METHOD MAPPING + +=head3 C<POST {method}> + +Вызывает метод C<method>, в отличии от C<GET> методы опубликованные через C<POST> могут вносить +изменения в объекты. + +=head1 MEMBERS + +=head2 C<[get]target> + +Объект (также может быть и класс), обеспечивающий функционал ресурса. + +=head2 C<[get]methods> + +=head2 C<[get]childRegex> + +=head2 C<[get]fetch> + +=head2 C<[get]list> + +=head2 C<[get]insert> + +=head2 C<[get]update> + +=head2 C<[get]delete> + +=head2 C<GetImpl($child,$action)> + +=head2 C<PutImpl($child,$action)> + +=head2 C<PostImpl($child,$action)> + +=head2 C<DeleteImpl($child,$action)> + +=head2 C<InvokeMember($memberInfo,$child,$action)> + =cut \ No newline at end of file