File Coverage

blib/lib/Articulate/Service.pm
Criterion Covered Total %
statement 34 55 61.8
branch 0 6 0.0
condition 0 3 0.0
subroutine 10 14 71.4
pod 2 3 66.6
total 46 81 56.7


line stmt bran cond sub pod time code
1             package Articulate::Service;
2 10     10   46 use strict;
  10         14  
  10         317  
3 10     10   38 use warnings;
  10         15  
  10         250  
4              
5 10     10   1773 use Articulate::Syntax;
  10         25  
  10         49  
6              
7             # The following provide objects which must be created on a per-request basis
8 10     10   7615 use Articulate::Request;
  10         17  
  10         154  
9 10     10   2996 use Articulate::Response;
  10         21  
  10         42  
10              
11 10     10   2611 use Moo;
  10         37  
  10         49  
12              
13             with 'Articulate::Role::Service';
14 10     10   9282 use Try::Tiny;
  10         11012  
  10         571  
15 10     10   63 use Scalar::Util qw(blessed);
  10         14  
  10         476  
16              
17 10     10   59 use Exporter::Declare;
  10         18  
  10         64  
18             default_exports qw(articulate_service);
19              
20             =head1 NAME
21              
22             Articulate::Service - provide an API to all the core Articulate features.
23              
24             =cut
25              
26             =head1 DESCRIPTION
27              
28             The Articulate Service provides programmatic access to all the core features of the Articulate app. It is the intermediary between the B and all other B.
29              
30             Mostly, you will want to be calling the service in routes, for instance:
31              
32             get 'zone/:zone_name/article/:article_name' => sub {
33             my ($zone_name, $article_name) = param('zone_name'), param('article_name');
34             return $self->process_request ( read => "/zone/$zone_name/article/$article_name' )
35             }
36              
37             However, you may also want to call it from one-off scripts, tests, etc., especially where you want to perform tasks which you don't want to make available in routes, or where you are already in a perl environment and mapping to the HTTP layer would be a distraction. In theory you could create an application which did not have any web interface at all using this service, e.g. a command-line app on a shared server.
38              
39             =cut
40              
41             sub articulate_service {
42 0     0 0 0 __PACKAGE__->new(@_);
43             }
44              
45             has providers => (
46             is => 'rw',
47             default => sub { [] },
48             coerce => sub { instantiate_array(@_) },
49             );
50              
51             =head3 process_request
52              
53             my $response = service->process_request($request);
54             my $response = service->process_request($verb => $data);
55              
56             This is the primary method of the service: Pass in an Articulate::Request object and the Service will produce a Response object to match.
57              
58             Alternatively, if you pass a string as the first argument, the request will be created from the verb and the data.
59              
60             Which verbs are handled, what data they require, and how they will be processed are determined by the service providers you have set up in your config: C passes the request to each of the providers in turn and asks them to process the request.
61              
62             Providers can decline to process the request by returning undef, which will cause the service to offer the requwst to the next provider.
63              
64             Note that a provider MAY act on a request and still return undef, e.g. to perform logging, however it is discouraged to perform acctions which a user would typically expect a response from (e.g. a create action should return a response and not just pass to a get to confirm it has successfully created what it was suppsed to).
65              
66             =cut
67              
68             sub process_request {
69 0     0 1 0 my $self = shift;
70 0         0 my @underscore = @_; # because otherwise the try block will eat it
71 0         0 my $request;
72 0         0 my $response = response error => {
73             error => Articulate::Error::NotFound->new(
74             { simple_message => 'No appropriate Service Provider found' }
75             )
76             };
77             try {
78 0 0   0   0 if ( ref $underscore[0] ) {
79 0         0 $request = $underscore[0];
80             }
81             else { # or accept $verb => $data
82 0         0 $request = articulate_request(@underscore);
83             }
84 0         0 foreach my $provider ( @{ $self->providers } ) {
  0         0  
85 0         0 $provider->app( $self->app );
86 0         0 my $resp = $provider->process_request($request);
87 0 0       0 if ( defined $resp ) {
88 0         0 $response = $resp;
89 0         0 last;
90             }
91             }
92             }
93             catch {
94 0     0   0 local $@ = $_;
95 0 0 0     0 if ( blessed $_ and $_->isa('Articulate::Error') ) {
96 0         0 $response = response error => { error => $_ };
97             }
98             else {
99 0         0 $response =
100             response error => { error =>
101             Articulate::Error->new( { simple_message => 'Unknown error' . $@ } )
102             };
103             }
104 0         0 };
105 0         0 return $response;
106             }
107              
108             =head3 enumerate_verbs
109              
110             my @verbs = @{ $self->enumerate_verbs };
111              
112             Returns an arrayref of verbs which at list one provider will process.
113              
114             =cut
115              
116             sub enumerate_verbs {
117 1     1 1 27 my $self = shift;
118 1         1 my $verbs = {};
119 1         2 foreach my $provider ( @{ $self->providers } ) {
  1         11  
120 5         896 $verbs->{$_}++ foreach keys %{ $provider->verbs };
  5         16  
121             }
122 1         30 return [ sort keys %$verbs ];
123             }
124              
125             =head1 SEE ALSO
126              
127             =over
128              
129             =item * L
130              
131             =item * L
132              
133             =item * L
134              
135             =back
136              
137             =cut
138              
139             1;