line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ************************************************************************* |
2
|
|
|
|
|
|
|
# Copyright (c) 2014-2022, SUSE LLC |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# All rights reserved. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# Redistribution and use in source and binary forms, with or without |
7
|
|
|
|
|
|
|
# modification, are permitted provided that the following conditions are met: |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# 1. Redistributions of source code must retain the above copyright notice, |
10
|
|
|
|
|
|
|
# this list of conditions and the following disclaimer. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright |
13
|
|
|
|
|
|
|
# notice, this list of conditions and the following disclaimer in the |
14
|
|
|
|
|
|
|
# documentation and/or other materials provided with the distribution. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# 3. Neither the name of SUSE LLC nor the names of its contributors may be |
17
|
|
|
|
|
|
|
# used to endorse or promote products derived from this software without |
18
|
|
|
|
|
|
|
# specific prior written permission. |
19
|
|
|
|
|
|
|
# |
20
|
|
|
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
21
|
|
|
|
|
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22
|
|
|
|
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23
|
|
|
|
|
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
24
|
|
|
|
|
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25
|
|
|
|
|
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26
|
|
|
|
|
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27
|
|
|
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28
|
|
|
|
|
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29
|
|
|
|
|
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30
|
|
|
|
|
|
|
# POSSIBILITY OF SUCH DAMAGE. |
31
|
|
|
|
|
|
|
# ************************************************************************* |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use 5.012; |
35
|
22
|
|
|
22
|
|
240462
|
use strict; |
|
22
|
|
|
|
|
77
|
|
36
|
22
|
|
|
22
|
|
100
|
use warnings; |
|
22
|
|
|
|
|
40
|
|
|
22
|
|
|
|
|
523
|
|
37
|
22
|
|
|
22
|
|
110
|
|
|
22
|
|
|
|
|
40
|
|
|
22
|
|
|
|
|
618
|
|
38
|
|
|
|
|
|
|
use App::CELL qw( $CELL $log $meta $core $site ); |
39
|
22
|
|
|
22
|
|
112
|
use App::CELL::Test qw( _touch ); |
|
22
|
|
|
|
|
52
|
|
|
22
|
|
|
|
|
2759
|
|
40
|
22
|
|
|
22
|
|
312
|
use Data::Dumper; |
|
22
|
|
|
|
|
47
|
|
|
22
|
|
|
|
|
1007
|
|
41
|
22
|
|
|
22
|
|
118
|
use File::ShareDir; |
|
22
|
|
|
|
|
31
|
|
|
22
|
|
|
|
|
893
|
|
42
|
22
|
|
|
22
|
|
199
|
use Log::Any::Adapter; |
|
22
|
|
|
|
|
37
|
|
|
22
|
|
|
|
|
790
|
|
43
|
22
|
|
|
22
|
|
842
|
use Params::Validate qw( :all ); |
|
22
|
|
|
|
|
795
|
|
|
22
|
|
|
|
|
203
|
|
44
|
22
|
|
|
22
|
|
641
|
#use Try::Tiny; |
|
22
|
|
|
|
|
36
|
|
|
22
|
|
|
|
|
3137
|
|
45
|
|
|
|
|
|
|
use Web::Machine; |
46
|
22
|
|
|
22
|
|
853
|
|
|
22
|
|
|
|
|
180619
|
|
|
22
|
|
|
|
|
12226
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 NAME |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Web::MREST - Minimalistic REST server |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 VERSION |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Version 0.290 |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=cut |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
our $VERSION = '0.290'; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head2 Development status |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
L<Web::MREST> is currently in "Alpha - feature freeze". There are almost |
69
|
|
|
|
|
|
|
certainly bugs lurking in the code, but all features have been implemented. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 SYNOPSIS |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
To take this module for a spin, execute this command: |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
$ mrest-standalone |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Leave this running, and from another console start the command-line client: |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
$ mrest-cli |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
In the CLI client, type e.g. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Web::MREST::CLI::Parser> get / |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
A 'GET' request will be sent for the root resource and the CLI client |
89
|
|
|
|
|
|
|
will display a representation of the response. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
A similar result can be obtained using C<curl>: |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
curl -v http://localhost:5000/ -X GET -H "Content-Type: application/json" |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
For more information on using the CLI client, see L<Web::MREST::CLI>. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 DESCRIPTION |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
MREST stands for "minimalistic" or "mechanical" REST server. (Mechanical because |
102
|
|
|
|
|
|
|
it relies on L<Web::Machine>.) |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
L<Web::MREST> provides a fully functional REST server that can be started |
105
|
|
|
|
|
|
|
with a simple command. Without modification, the server provides a set of |
106
|
|
|
|
|
|
|
generalized resources that can be used to demonstrate how the REST server |
107
|
|
|
|
|
|
|
works, or for testing. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Developers can use L<Web::MREST> as a platform for implementing their own |
110
|
|
|
|
|
|
|
REST servers, as described below. L<App::Dochazka::REST> is a "real-world" |
111
|
|
|
|
|
|
|
example of such a server. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
For an introduction to REST and Web Services, see |
114
|
|
|
|
|
|
|
L<Web::MREST::WebServicesIntro>. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head1 RFC2616 AS A STATE MACHINE |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
RFC2616 is, of course, the HTTP 1.1 standard - not a state machine. But |
121
|
|
|
|
|
|
|
the authors of "Web Machine" (which was originally implemented in Erlang) had a |
122
|
|
|
|
|
|
|
neat idea to represent it as a state machine and use this to implement a server |
123
|
|
|
|
|
|
|
for providing web services. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
L<Web::Machine> is, of course, the Perl port of Web Machine. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
L<Web::MREST> relies on L<Web::Machine> to implement RFC2616. L<Web::MREST> |
128
|
|
|
|
|
|
|
can be thought of as an additional abstraction layer over L<Web::Machine>. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
By itself, L<Web::Machine> is not a server. It does not listen on a port, for |
131
|
|
|
|
|
|
|
example. Instead, it is designed to work (via L<Plack>) with a |
132
|
|
|
|
|
|
|
L<PSGI>-compliant web server. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
The web server hands incoming requests over to L<Web::Machine>, which runs the |
135
|
|
|
|
|
|
|
requests through its state machine. (The L<Web::Machine> authors refer to the |
136
|
|
|
|
|
|
|
state machine as "the FSM.") The best way to grasp the state machine is to |
137
|
|
|
|
|
|
|
envision it as a flow-chart. At each "decision node" of the flow-chart - where |
138
|
|
|
|
|
|
|
flow can go in one of two directions - L<Web::Machine> calls the method |
139
|
|
|
|
|
|
|
corresponding to that node. Each node is designated by a letter and a number: |
140
|
|
|
|
|
|
|
e.g. F7, O18, etc. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
The flow-chart implemented by the FSM can be found L<here|http://...> - you are |
143
|
|
|
|
|
|
|
encouraged to have that open for reference while reading this documentation |
144
|
|
|
|
|
|
|
and implementing your REST server. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 SERVER STARTUP AND INHERITANCE SCHEME |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 Standalone mode |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
As stated above, L<Web::MREST> is capable of operating independently. To try |
155
|
|
|
|
|
|
|
it out, start up the server like this: |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
$ mrest-standalone |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
And then point your browser to |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
http://localhost:5000 |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
If you look inside the C<mrest-standlone> script, you will see that it is |
164
|
|
|
|
|
|
|
just a wrapper for the C<mrest> script, which takes two mandatory options. The |
165
|
|
|
|
|
|
|
first, C<--distro>, is the name of the distribution in whose sharedir it should |
166
|
|
|
|
|
|
|
look for configuration files. The second, C<--module>, is the name of the |
167
|
|
|
|
|
|
|
application's resource module, i.e. the ultimate module in the chain of |
168
|
|
|
|
|
|
|
inheritance. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
In standalone mode, the actual command that is run is: |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
mrest --distro=Web::MREST --module=Web::MREST::Dispatch |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
which causes the chain of inheritance to be built up as follows: |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=over |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=item C<bin/mrest> |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
calls C<< Web::Machine->new >>; the L<Web::Machine> object is blessed into L<Web::MREST::Dispatch> |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item L<Web::MREST::Dispatch> |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
inherits from L<Web::MREST::Entity> |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item L<Web::MREST::Entity> |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
inherits from L<Web::MREST::Resource> |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item L<Web::MREST::Resource> |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
inherits from L<Web::Machine::Resource> |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=back |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
When you browse to C<http://0:5000> in standalone mode, you get a list of the |
197
|
|
|
|
|
|
|
sample REST resources that are available. For more information on these, see |
198
|
|
|
|
|
|
|
C<config/dispatch_Config.pm>. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 With your application |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Starting the server with your application is the same as described in |
204
|
|
|
|
|
|
|
L<"Standalone mode">, above, except that you replace C<Web-MREST> with the name |
205
|
|
|
|
|
|
|
of your distribution and C<Web::MREST::Dispatch> with the name of your ultimate |
206
|
|
|
|
|
|
|
resource module. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
$ mrest YourApp-MREST YourApp::MREST::Dispatch |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
For example, here we are starting the server with the distribution |
211
|
|
|
|
|
|
|
C<YourApp-MREST>, which is presumed to implement a chain of inheritance |
212
|
|
|
|
|
|
|
similar to L<Web::MREST>'s, i.e.: |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
Web::MREST -> YourApp::MREST::Resource -> YourApp::MREST::Dispatch |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Thanks to this arrangement, the application developer can customize |
217
|
|
|
|
|
|
|
L<Web::MREST> - i.e., not only providing her own resources and handlers, |
218
|
|
|
|
|
|
|
but even altering how the state machine operates, if necessary - by providing |
219
|
|
|
|
|
|
|
her own chain of inheritance and overriding various methods within it. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=head3 Recapitulation |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
Since the above is quite important, let's go over it again: |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
The L<Web::MREST> documentation will always refer to your application either |
227
|
|
|
|
|
|
|
as the "application" or as C<YourApp>. The application should take the form |
228
|
|
|
|
|
|
|
of a Perl distribution, which should have: |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=over |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item * a distribution sharedir |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item * a resource module, C<YourApp::Resource>. |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=item * a dispatch module, C<YourApp::Dispatch> |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=back |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
For now, just think of these three components as "black boxes". We will |
241
|
|
|
|
|
|
|
cover their contents later. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
The server (i.e. your application), is started by executing the C<mrest> |
244
|
|
|
|
|
|
|
executable with the name of your application's distribution and the name of its |
245
|
|
|
|
|
|
|
dispatch module, which should be the ultimate module in the chain of |
246
|
|
|
|
|
|
|
inheritance. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
$ mrest --distro YourApp --module YourApp::Dispatch |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Under the hood the startup script, which can be reviewed at C<bin/mrest>, |
251
|
|
|
|
|
|
|
does essentially this: |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
use Web::Machine; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Web::Machine->new( |
256
|
|
|
|
|
|
|
resource => 'YourApp::Dispatch', |
257
|
|
|
|
|
|
|
)->to_app; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
There are two key points concerning the L<Web::Machine> object constructed by |
260
|
|
|
|
|
|
|
call to C<< Web::Machine->new >>: |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=over |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item 1. the object is blessed into C<YourApp::Dispatch> |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=item 2. the object is a L<Plack> application |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=back |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head1 INHERITANCE SCHEME |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
As seen in the previous section, C<YourApp> inherits from |
275
|
|
|
|
|
|
|
L<Web::MREST> via a chain of inheritance. Here is the chain implemented by L<Web::MREST>: |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
-> Web::MREST::Dispatch |
279
|
|
|
|
|
|
|
-> Web::MREST::Entity |
280
|
|
|
|
|
|
|
-> Web::MREST::Resource |
281
|
|
|
|
|
|
|
-> Web::Machine::Resource |
282
|
|
|
|
|
|
|
-> Plack::Component |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Assuming L<YourApp> has its authentication and authorization routines |
285
|
|
|
|
|
|
|
in L<YourApp::Resource> and its resource definitions and handlers in |
286
|
|
|
|
|
|
|
L<YourApp::Dispatch>, the chain for L<YourApp> would look like this: |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
-> YourApp::Dispatch |
289
|
|
|
|
|
|
|
-> YourApp::Resource |
290
|
|
|
|
|
|
|
-> Web::MREST::Entity |
291
|
|
|
|
|
|
|
-> Web::MREST::Resource |
292
|
|
|
|
|
|
|
-> Web::Machine::Resource |
293
|
|
|
|
|
|
|
-> Plack::Component |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
(In other words, L<YourApp::Dispatch> and L<YourApp::Resource> replace |
296
|
|
|
|
|
|
|
L<Web::MREST::Dispatch>, which is just a demo.) |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
When L<Web::Machine> reaches a given node in the FSM, it calls the |
299
|
|
|
|
|
|
|
corresponding method on that L<Web::Machine> object. Since the object is |
300
|
|
|
|
|
|
|
blessed into C<YourApp::Dispatch>, that module is where Perl will |
301
|
|
|
|
|
|
|
start to look for the method. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
If the method is not found at the lowest level, Perl follows the chain of |
304
|
|
|
|
|
|
|
inheritance "upward". The highest level, L<Plack::Component>, is shown only for |
305
|
|
|
|
|
|
|
completeness - L<Web::MREST::Resource> and L<Web::MREST::Entity> implement |
306
|
|
|
|
|
|
|
all the methods that your resource module might (or should) want to override. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Readers who are not well-versed in writing Perl applications that use |
309
|
|
|
|
|
|
|
inheritance are referred to the fine Perl manuals such as C<perlootut>. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head1 STATE MACHINE INTRODUCTION |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
At this point we have enough background information to begin to grasp the state |
316
|
|
|
|
|
|
|
machine. (Instead of writing "state machine" we will follow the L<Web::Machine> |
317
|
|
|
|
|
|
|
convention of referring to it as the "FSM".) This section presents selected |
318
|
|
|
|
|
|
|
features and nodes of the FSM, how L<Web::MREST> implements them, and how to |
319
|
|
|
|
|
|
|
use them. The discourse proceeds in the order in which the methods are called |
320
|
|
|
|
|
|
|
when an HTTP request enters the FSM. We can envision these method calls as |
321
|
|
|
|
|
|
|
decision nodes of a flow-chart, or "cogs" of the FSM. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
And we needn't just imagine the flow-chart - it actually exists and can be |
324
|
|
|
|
|
|
|
downloaded from L<...>. If you want to understand how L<Web::Machine> and |
325
|
|
|
|
|
|
|
L<Web::MREST> work, this document is of fundamental importance. Hereinafter |
326
|
|
|
|
|
|
|
it will be referred to as "the FSM diagram". |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
As you can see in the FSM diagram, each FSM cog has a code like C<B6>, for ease |
329
|
|
|
|
|
|
|
of reference. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head1 POLICIES AND FEATURES |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
L<Web::Machine> implements the FSM, and that's all it does. In particular, it |
336
|
|
|
|
|
|
|
imposes no policies on distributions that use it. By taking this approach, |
337
|
|
|
|
|
|
|
L<Web::Machine> maximizes its range of potential uses. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Powerful as it is, L<Web::Machine> can be confusing to use. When I started |
340
|
|
|
|
|
|
|
writing my first application based on it, I found myself wanting an |
341
|
|
|
|
|
|
|
intermediate module between my application and L<Web::Machine> - something that |
342
|
|
|
|
|
|
|
would make L<Web::Machine> a little more friendly. |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
L<Web::MREST> is that module. It builds on L<Web::Machine> in an effort to |
345
|
|
|
|
|
|
|
provide certain additional features. Inevitably, this means imposing some |
346
|
|
|
|
|
|
|
policies (i.e., limitations) on users. To me that seems like an acceptable |
347
|
|
|
|
|
|
|
trade-off. |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 Path dispatch |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
A key part of any web application is "path dispatch" (i.e. URI translation), |
353
|
|
|
|
|
|
|
which answers the question: "how are URIs mapped to resources?" |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
Although L<Web::Machine> provides a way to specify handlers for various media |
356
|
|
|
|
|
|
|
types that may appear in request and response entities, it provides no |
357
|
|
|
|
|
|
|
way of getting from the URI to the handler. L<Web::MREST> bridges this gap |
358
|
|
|
|
|
|
|
by providing a system of resource definitions (see L<"Resource definitions">, |
359
|
|
|
|
|
|
|
below). |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
The definition of each resource specifies the URI-to-resource mapping and |
362
|
|
|
|
|
|
|
provides the name of the resource's handler method. Internally, L<Web::MREST> |
363
|
|
|
|
|
|
|
uses a single L<Path::Router> object to parse URIs. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Before any URIs can be parsed, this L<Path::Router> object must be initialized. |
366
|
|
|
|
|
|
|
This is done in L<Web::MREST::Resource>, in the C<service_available> method. |
367
|
|
|
|
|
|
|
That method checks the scalar variable that is supposed to contain the |
368
|
|
|
|
|
|
|
L<Path::Router> object and, if needed, calls the C<init_router> method to |
369
|
|
|
|
|
|
|
initialize it. |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
In the L<Web::MREST> demo application, C<init_router> is implemented in |
372
|
|
|
|
|
|
|
L<Web::MREST::Dispatch>. |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 Resource handlers |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
The L<Web::Machine> documentation mentions "handlers" but doesn't go into |
378
|
|
|
|
|
|
|
any detail on how to write them. L<Web::MREST> not only provides some working |
379
|
|
|
|
|
|
|
resource handlers, but also implements a paradigm for writing them. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
In this paradigm, the handler is called as a method, just like any of the other |
382
|
|
|
|
|
|
|
methods in the chain of inheritance. (To avoid namespace issues, it is |
383
|
|
|
|
|
|
|
recommended that handler method names start with C<handler_>.) The name of the |
384
|
|
|
|
|
|
|
method is specified in the resource definition. |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
The handler method is called twice - in other words, there are two passes. In |
387
|
|
|
|
|
|
|
the first pass, the handler is called with the argument C<1> (scalar value) and |
388
|
|
|
|
|
|
|
is expected to return a boolean value indicating whether the resource exists. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
In the second pass, indicated by the argument C<2> (scalar value), the handler |
391
|
|
|
|
|
|
|
is expected to return a C<App::CELL::Status> object. This object (rendered in |
392
|
|
|
|
|
|
|
JSON) becomes the response entity unless overrided by a declared status (see |
393
|
|
|
|
|
|
|
C<mrest_declare_status> in L<Web::MREST::Resource>. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
B<N.B.:> The request entity is not available to the handler (via |
396
|
|
|
|
|
|
|
C<$self->context->{request_entity}> until the second pass! |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head2 Status objects |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
As mentioned in the previous section, L<App::CELL::Status> objects are returned |
402
|
|
|
|
|
|
|
by resource handlers. Not only that - L<Web::MREST> tries its best to I<always> |
403
|
|
|
|
|
|
|
return an L<App::CELL::Status> object in the response entity. |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Actually, it is not the object itself that is returned, but a JSON |
406
|
|
|
|
|
|
|
representation of its underlying data structure. From this, the object can |
407
|
|
|
|
|
|
|
easily be reconstituted on the client side by doing |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
my $status = $JSON->decode( $response_entity ); |
410
|
|
|
|
|
|
|
bless $status, 'App::CELL::Status'; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
For more on what status objects can do, see L<App::CELL::Status>, L<App::CELL>, |
413
|
|
|
|
|
|
|
and L<App::CELL::Guide>. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=head2 Error statuses |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
L<Web::Machine> always tries to return the proper HTTP status code in the |
419
|
|
|
|
|
|
|
response. The application developer will likely need to "force" a code in |
420
|
|
|
|
|
|
|
certain cases. For example, the request may be "malformed" in a way that is |
421
|
|
|
|
|
|
|
not discoverable until the handler runs. Or, caught exceptions may need to be |
422
|
|
|
|
|
|
|
exposed to the client with C<500 - Internal Error>. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
Also, the RFC says |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
. . . the server SHOULD include an entity containing an explanation of the |
427
|
|
|
|
|
|
|
error situation, and whether it is a temporary or permanent condition. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Clearly, then, a mechanism is needed for providing such explanations and |
430
|
|
|
|
|
|
|
indicating whether the error is temporary or permanent. And that mechanism |
431
|
|
|
|
|
|
|
should enable an arbitrary status code to be declared. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
By itself, L<Web::Machine> does not really provide such a mechanism. What it |
434
|
|
|
|
|
|
|
does provide is a mechanism for "forcing" an arbitrary status code (e.g. C<404 |
435
|
|
|
|
|
|
|
- Not Found>) by returning a scalar reference. This mechanism has two |
436
|
|
|
|
|
|
|
disadvantages: |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=over |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=item it is only available at certain junctions of the FSM |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
I wanted a way to "declare" a status code at any point and be certain that |
443
|
|
|
|
|
|
|
L<Web::Machine> won't change it later on. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=item there is no obvious way to provide an explanation of the error |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
L<Web::Machine> considers this an implementation detail. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=back |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Hence, L<Web::MREST> provides the C<mrest_declare_status> method. To learn |
452
|
|
|
|
|
|
|
how to call it and how it works, see L<Web::MREST::Resource>. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head1 THE FINE STATE MACHINE |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
In this section we take a detailed look at the FSM by considering some common |
459
|
|
|
|
|
|
|
scenarios. For our purposes these are C<GET>, C<POST>, C<PUT>, and C<DELETE> |
460
|
|
|
|
|
|
|
requests. Handling can differ according to whether or not a C<POST> creates a |
461
|
|
|
|
|
|
|
new resource and whether or not the resource is determined to exist. |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=head2 Part One (sanity checks and information gathering) |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
The first few cogs are executed, in the same order, on all requests regardless |
466
|
|
|
|
|
|
|
of method. They can be thought of both as a set of sanity checks and as an |
467
|
|
|
|
|
|
|
information-gathering process. |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head3 C<service_available> (B13) |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
The first method call is C<service_available>, which is implemented by |
473
|
|
|
|
|
|
|
L<Web::MREST::Resource> and should I<not> be implemented by your application, |
474
|
|
|
|
|
|
|
because it calls C<init_router> to ensure that all the resource definitions are |
475
|
|
|
|
|
|
|
loaded and the L<Path::Router> singleton is properly initialized. |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
This is not really a limitation, however. Whatever code you need to run here |
478
|
|
|
|
|
|
|
can be placed in a method called C<mrest_service_available>, which should |
479
|
|
|
|
|
|
|
return a boolean value (i.e. 1 or 0), which determines the return value from |
480
|
|
|
|
|
|
|
the method. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
If the service really isn't available, you can return false, which will trigger |
483
|
|
|
|
|
|
|
a C<503 Service Not Available> response. Before returning you should do: |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
$self->mrest_declare_status( explanation => '...', permanent => 0 ); |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
to provide an explanation of what is going on. |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
For details, see the C<t/503-Service-Unavailable.t> unit test. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head3 C<known_methods> (B12) |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Returns the list of supported ("known") methods in |
495
|
|
|
|
|
|
|
C<< $site->MREST_SUPPORTED_HTTP_METHODS >>. If the request method is not |
496
|
|
|
|
|
|
|
in that list, a C<501 Not Implemented> response is returned along with |
497
|
|
|
|
|
|
|
an explanation that the method requested is not supported. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
If this behavior is not appropriate, the method can be implemented by the |
500
|
|
|
|
|
|
|
application. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head3 C<uri_too_long> (B11) |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
If the request URI is longer than the value set in the C<MREST_MAX_LENGTH_URI> site parameter, |
506
|
|
|
|
|
|
|
the client will receive a C<414 Request URI Too Long> response. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
To override this behavior, provide your own C<uri_too_long> routine in your |
509
|
|
|
|
|
|
|
resource module. |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
This functionality is demonstrated by the C<t/414-Request-URI-Too-Long.t> unit. |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head3 C<allowed_methods> (B10) |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
"Is the method allowed on this resource?" |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
This next routine is where things start to get complicated. According to the |
519
|
|
|
|
|
|
|
L<Web::Machine::Resource |
520
|
|
|
|
|
|
|
documentation|https://metacpan.org/pod/Web::Machine::Resource#allowed_methods>, |
521
|
|
|
|
|
|
|
we are expected to respond with a list of methods allowed on the resource. To |
522
|
|
|
|
|
|
|
assemble such a list, we must first answer two questions: |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=over |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=item 1. Have the resource definitions been loaded? |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=item 2. Does the URI match a known resource? |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=back |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
After the server starts, the first time this method is called triggers a |
533
|
|
|
|
|
|
|
call to the C<init_router> method, which populates the C<$resources> package |
534
|
|
|
|
|
|
|
variable in C<Web::MREST::InitRouter> with all the resource definitions. |
535
|
|
|
|
|
|
|
This is explained in detail in L<"Resource definitions">. This takes care of |
536
|
|
|
|
|
|
|
the first question. |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
The second question is answered by C<Path::Router>. Once the request has |
539
|
|
|
|
|
|
|
been associated with a known resource, completing our task becomes a matter of |
540
|
|
|
|
|
|
|
getting and returning the set of methods for which the resource is defined. |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head3 C<malformed_request> (B9) |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
A true return value from this method triggers a "400 Bad Request" response |
546
|
|
|
|
|
|
|
status. RFC2616 does not stipulate exactly what constitutes a bad request. |
547
|
|
|
|
|
|
|
We already (in allowed_methods) took care of the case when the URI |
548
|
|
|
|
|
|
|
fails to match a known resource, and that includes applying any C<validations> |
549
|
|
|
|
|
|
|
properties from the resource definition. |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
So, in this method (or your overlay) we take the "next step" (whatever that is) |
552
|
|
|
|
|
|
|
in vetting the request. Keep in mind that this method is called before |
553
|
|
|
|
|
|
|
the resource handler. If you have any sanity checks you wish to apply _after_ |
554
|
|
|
|
|
|
|
the URI is matched to a resource but _before_ the resource handler fires, this |
555
|
|
|
|
|
|
|
is the place to put them. |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
If you would like to keep L<Web::MREST>'s implementation of this method |
558
|
|
|
|
|
|
|
(which, for example, pushes the Content-Length and Content-Type information |
559
|
|
|
|
|
|
|
onto the context) and add your own logic, you can put it in |
560
|
|
|
|
|
|
|
C<mrest_malformed_request> instead of overriding C<malformed_request> itself. |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
If you intend to return false from this method you should first do this: |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
$self->mrest_declare_status( explanation => '...' ); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
to ensure that an explanation is included with the 400 response. |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=head3 C<is_authorized> (B8) |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
In my mind, "authentication" is the process of determining who the user |
572
|
|
|
|
|
|
|
is, and "authorization" determines if the user is allowed to do what she |
573
|
|
|
|
|
|
|
is asking to do. However, RFC2616 does not make such a clear distinction. |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
For that reason, it is left to the application to implement this method |
576
|
|
|
|
|
|
|
if needed. |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=head3 C<forbidden> (B7) |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
The same thoughts as expressed under C<is_authorized>, above, apply to |
582
|
|
|
|
|
|
|
this method as well. |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head3 C<valid_content_headers> (B6) |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
This is where you vet the C<Content-*> headers in the request. If the |
588
|
|
|
|
|
|
|
request contains any invalid C<Content-*> headers (i.e., if the '*' part |
589
|
|
|
|
|
|
|
does not appear in << $site->MREST_VALID_CONTENT_HEADERS >>), |
590
|
|
|
|
|
|
|
a 501 will be generated. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
The content headers are passed to the method in a L<Hash::MultiValue> |
593
|
|
|
|
|
|
|
object. |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=head3 C<known_content_type> (B5) |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
If the C<Content-Type> header is relevant - i.e., if this is a PUT or |
599
|
|
|
|
|
|
|
POST request and if there is a request entity - check it against |
600
|
|
|
|
|
|
|
<< $site->MREST_SUPPORTED_CONTENT_TYPES >>. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=head3 C<valid_entity_length> (B4) |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
A simple routine that compares the entity length (in bytes) with the |
606
|
|
|
|
|
|
|
maximum set in C<< $site->MREST_MAX_LENGTH_REQUEST_BODY >>. |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=head3 C<options> (B3) |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
If your application needs to support the C<OPTIONS> method, you should |
612
|
|
|
|
|
|
|
implement this yourself - otherwise, ignore it. |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head2 Part Two (content negotioation) |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
The HTTP standard provides some complicated logic to enable clients |
618
|
|
|
|
|
|
|
and servers to "negotiate" the format (media type), language, encoding, |
619
|
|
|
|
|
|
|
etc. in which content will be passed back and forth. Here in the L<Web::MREST> |
620
|
|
|
|
|
|
|
documentation we gloss over this complexity and focus only on the media type. |
621
|
|
|
|
|
|
|
However, L<Web::Machine> includes methods for handling all the content |
622
|
|
|
|
|
|
|
negotiation decision nodes and the application developer is free to take |
623
|
|
|
|
|
|
|
advantage of them. |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
That said, L<Web::MREST> itself provides JSON handlers for both the request and |
626
|
|
|
|
|
|
|
the response entities, and should be fully UTF-8 clean. Hopefully, this will |
627
|
|
|
|
|
|
|
save application developers some work. (For more information, see L<"STATUS |
628
|
|
|
|
|
|
|
OBJECTS AND ERROR HANDLING">.) |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
The following subsections detail the principal content negotiation methods. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head3 C<content_types_provided> |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
As the L<Web::Machine::Resource> documentation states, this method must be |
635
|
|
|
|
|
|
|
implemented (i.e., by the application) - otherwise, "your resource will not be |
636
|
|
|
|
|
|
|
able to return any useful content". |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
Quoting further: "This should return an ARRAY of HASH ref pairs where the key |
639
|
|
|
|
|
|
|
is the name of the media type and the value is a CODE ref (or name of a method) |
640
|
|
|
|
|
|
|
which can provide a resource representation in that media type." |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
The implementation provided by L<Web::MREST> allows clients to specify (via |
643
|
|
|
|
|
|
|
an C<Accept> header) one of two media types: |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=over |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=item C<text/html> |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Since it is the first hashref pair of the two, it is the default. That means |
650
|
|
|
|
|
|
|
if the incoming request does not have an C<Accept> header, the handler |
651
|
|
|
|
|
|
|
specified for C<text/html> will be called to generate the response entity. |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=item C<application/json> |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
This is the media type that L<Web::MREST> was written to support, both in |
656
|
|
|
|
|
|
|
request entities and in response entities. However, there is nothing preventing |
657
|
|
|
|
|
|
|
you as the application developer from specifying handlers for other media types. |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
=back |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
If the request includes an C<Accept> header, but none of the media types |
662
|
|
|
|
|
|
|
specified in it are found in C<content_types_provided>, L<Web::Machine> will |
663
|
|
|
|
|
|
|
generate a C<406 Not Acceptable> response. (Unfortunately, there is no easy way |
664
|
|
|
|
|
|
|
for L<Web::MREST> or the application to know in advance that this error will be |
665
|
|
|
|
|
|
|
triggered, so it will be returned "bare" - i.e., without any explanatory |
666
|
|
|
|
|
|
|
response entity.) |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
In the normal case when an acceptable handler exists, it will be called to |
669
|
|
|
|
|
|
|
generate the response - in other words, whatever is returned by the chosen |
670
|
|
|
|
|
|
|
handler becomes the response entity, unless an error occurs inside the handler. |
671
|
|
|
|
|
|
|
In that case, the handler should return a reference to a scalar value |
672
|
|
|
|
|
|
|
(e.g., \400), which L<Web::Machine> will interpret as an HTTP response code. |
673
|
|
|
|
|
|
|
See L<"STATUS OBJECTS AND ERROR HANDLING">. |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
For more on response entity generation, see the sections dedicated to the |
676
|
|
|
|
|
|
|
various HTTP methods (L<"GET">, L<"PUT">, L<"POST">, L<"DELETE">), below. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=head3 C<content_types_accepted> |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
When the client sends C<PUT> or C<POST> requests, it will typically provide a |
682
|
|
|
|
|
|
|
'Content-Type' header specifying the media type of the bytes it is sending in |
683
|
|
|
|
|
|
|
the request body. This content type is compared with the media types returned |
684
|
|
|
|
|
|
|
by this method. If there is no match, L<Web::Machine> returns a C<415 |
685
|
|
|
|
|
|
|
Unsupported Media Type> error response. (Unfortunately, there is no easy way |
686
|
|
|
|
|
|
|
for L<Web::MREST> or the application to know in advance that this error will be |
687
|
|
|
|
|
|
|
triggered, so it will be returned "bare" - i.e., without any explanatory |
688
|
|
|
|
|
|
|
response entity.) |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
=head3 Other methods |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
For handling character sets, encodings, and languages, L<Web::Machine> provides |
694
|
|
|
|
|
|
|
a number of other content negotiation methods: |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=over |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=item C<charsets_provided> |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=item C<default_charset> |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=item C<languages_provided> |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=item C<encodings_provided> |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=item C<variances> |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=back |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
However, they are only needed if the application does complex content |
711
|
|
|
|
|
|
|
negotiation. |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head2 Part Three (resource existence) |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
When we have made it past content negotiation, we know more than just which |
717
|
|
|
|
|
|
|
routines will be used to process the request entity (if any) and generate the |
718
|
|
|
|
|
|
|
response. We have gathered quite a bit of information about the request. All |
719
|
|
|
|
|
|
|
this information has been pushed onto the context, so it is available to all |
720
|
|
|
|
|
|
|
our resource methods, including the resource handler which we will get to |
721
|
|
|
|
|
|
|
presently. This information includes: |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
(FIXME: verify this list as it is outdated) |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=over |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=item C<method> |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
The request method |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=item C<resource_name> |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
The resource name, which can be used as a key to look up the full resource |
734
|
|
|
|
|
|
|
definition in the C<< $Web::MREST::InitRouter::resources >> |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=item C<handler_name> |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
The name of the resource handler, e.g. C<handler_bugreport>. In L<Web::MREST>, |
739
|
|
|
|
|
|
|
the resource handlers reside in the L<Web::MREST::Dispatch> module. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=item C<uri> |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
The full URI provided with the request |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
=item C<uri_base> |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
The base part of the URI (e.g. "http://localhost:5000/" ) |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=item C<uri_path> |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
The relative path to the resource (e.g. "/bugreport") |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=item C<components> |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
Reference to an array the elements of which are the individual 'components' |
756
|
|
|
|
|
|
|
(i.e., everything between the '/' characters) of the C<uri_path> |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=item C<mapping> |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
A hashref mapping resource parameter names (if any) to their values |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=item C<content-length> |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
The content-length header. |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=item C<content-type> |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
The content-type header. |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=back |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
One major piece of information is missing, however: whether the resource exists |
773
|
|
|
|
|
|
|
or not. For that, we have to actually call the resource handler. |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=head3 C<resource_exists> (G7) |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
The term "resource" is not precisely defined. It can refer to the resource |
779
|
|
|
|
|
|
|
definition (a data structure), the resource handler (a Perl subroutine called |
780
|
|
|
|
|
|
|
as an object method), or an object (set of records) in an underlying database. |
781
|
|
|
|
|
|
|
Or it can refer to all of the above, or to something else. The following |
782
|
|
|
|
|
|
|
paragraphs describe L<Web::MREST>'s approach. |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
By the time control reaches this method, the request URI has already been |
785
|
|
|
|
|
|
|
matched to a resource definition. So the resource handler is known. Since we |
786
|
|
|
|
|
|
|
have no other way of knowing, we ask the resource itself, by calling the |
787
|
|
|
|
|
|
|
handler with the scalar value C<1> (i.e. the numeral 1) as the sole argument. |
788
|
|
|
|
|
|
|
This handler call is referred to as the "first pass". |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
How the handler is implemented does not concern us. We only ask that it return |
791
|
|
|
|
|
|
|
a boolean value (true or false) when called with this argument. If the return |
792
|
|
|
|
|
|
|
value from the handler is true, we can assume that the handler will be called |
793
|
|
|
|
|
|
|
again (second pass) in the response generation phase - read on. |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
=head2 Part Four (generation of response entity) |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
At this point we have |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
=over |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
=item gathered information about the request and placed it on the context |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
=item run the resource handler (first pass) to determine resource existence |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
=back |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
Up until now (i.e., through determination of resource existence), the FSM |
809
|
|
|
|
|
|
|
has been a series of steps applied, in the same order, regardless of the |
810
|
|
|
|
|
|
|
HTTP method. |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
In the sections below, we examine how responses are generated for each of |
813
|
|
|
|
|
|
|
four HTTP methods (C<GET>, C<PUT>, C<POST>, and C<DELETE>) when the resource |
814
|
|
|
|
|
|
|
exists and when it doesn't exist. |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=head3 Resource exists |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=head4 C<GET> |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
=over |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=item 1. C<content_types_provided> method call |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
First, C<content_types_provided> is called to determine the name of the |
825
|
|
|
|
|
|
|
method that is capable of generating the response in the required format. |
826
|
|
|
|
|
|
|
This method is the one we mean when we refer to the "response generator". |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=item 2. Response generator method call |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
Second, the response generator is called (from C<o18> in |
831
|
|
|
|
|
|
|
L<Web::Machine::FSM::States>). It is expected to always return an |
832
|
|
|
|
|
|
|
L<App::CELL::Status> object. If an error condition is detected, the |
833
|
|
|
|
|
|
|
handler should declare it using C<< $self->mrest_declare_status >> |
834
|
|
|
|
|
|
|
and then return a "non_ok" status. |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
=back |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
C<GET> is the only request method that demands a response entity |
839
|
|
|
|
|
|
|
in the format specified by the C<Accept> header. For the other methods, |
840
|
|
|
|
|
|
|
response entities are optional, but recommended. In practice, this |
841
|
|
|
|
|
|
|
means that we have to create them ourselves. |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
=head4 C<POST> |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
Here we have two possible paths, depending on the value returned by |
847
|
|
|
|
|
|
|
C<post_is_create>: |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=over |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
=item C<post_is_create> true |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
=over |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=item C<create_path> and C<create_path_after_handler> |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
If, and only if, C<post_is_create> is true, processing continues via |
858
|
|
|
|
|
|
|
C<create_path> and C<create_path_after_handler>. Depending on the value of the |
859
|
|
|
|
|
|
|
latter, the request handler (determined by consulting |
860
|
|
|
|
|
|
|
C<content_types_accepted>) is called either before or after C<create_path>. |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
The request handler should stage the response entity in preparation for |
863
|
|
|
|
|
|
|
finalization. The content type can be inferred from |
864
|
|
|
|
|
|
|
C<< $request->env->{'web.machine.context'} >>. |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
=item Finalization |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
Request is finalized by a call to C<finish_request>. |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=back |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=item C<post_is_create> false |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
If C<post_is_create> returns false, all bets are off. For reasons I do not |
875
|
|
|
|
|
|
|
understand, L<Web::Machine> does not consult C<content_types_provided> or |
876
|
|
|
|
|
|
|
C<content_types_accepted> on this type of request. The only thing it does is |
877
|
|
|
|
|
|
|
call C<process_post>, and so it is up to this method to do whatever needs to be |
878
|
|
|
|
|
|
|
done to generate an entity and get it into the response. |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
L<Web::MREST> helps by making sure that the content type is stored in the |
881
|
|
|
|
|
|
|
context (in the C<'content_type'> property), so C<process_post> can look |
882
|
|
|
|
|
|
|
there for it and generate the response entity accordingly. |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=back |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=head4 C<PUT> |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
On all C<PUT> requests, and those C<POST> requests that are handled as |
890
|
|
|
|
|
|
|
C<PUT> requests (see above), L<Web::Machine> uses the following process: |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=over |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
=item C<content_types_accepted> |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
This method is called to determine the name of the method that can process |
897
|
|
|
|
|
|
|
the request body. This method is expected not only to process the request |
898
|
|
|
|
|
|
|
body, but also to generate the response. Therefore, we refer to this |
899
|
|
|
|
|
|
|
method as the "response generator" for C<PUT> requests. |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=item Response generator method call |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
Next, the response generator is called. For C<PUT> requests, the response |
904
|
|
|
|
|
|
|
generator is determined from C<content_types_accepted> based on the Here again, the method referred |
905
|
|
|
|
|
|
|
to by C<content_types_provided> is not called by L<Web::Machine>, but the |
906
|
|
|
|
|
|
|
response generator is free to call C<content_types_provided> and find |
907
|
|
|
|
|
|
|
out the method itself, and call it. Or do something else. |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
When C<resource_exists> is true, the response generator is called from C<o14> |
910
|
|
|
|
|
|
|
in L<Web::Machine::FSM::States>. |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=back |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
Whenever a new resource is created, a C<Location> header is added to |
915
|
|
|
|
|
|
|
the response with the URI path of the new resource. |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
In general, we understand C<PUT> to be a request to write to a resource. |
918
|
|
|
|
|
|
|
Typically, this will involve either creating (INSERT) or modifying (UPDATE) one |
919
|
|
|
|
|
|
|
or more database records/objects. |
920
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
Therefore, it has to be possible for a URI to resolve to a resource that |
922
|
|
|
|
|
|
|
does not yet exist. For example: |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
PUT employee/nick/Bubba |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
There may or may not be an employee by the name of Bubba in the database, |
927
|
|
|
|
|
|
|
but if we have a resource called 'employee/nick/:nick', Path::Router will |
928
|
|
|
|
|
|
|
match it in C<allowed_methods> and the resource handler will be called in |
929
|
|
|
|
|
|
|
C<resource_exists> - up until this point, the same sequence of method |
930
|
|
|
|
|
|
|
calls is used for C<GET>, C<POST>, C<PUT>, and C<DELETE>. |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
L<Web::MREST> has no way of knowing whether there is an employee named Bubba. |
933
|
|
|
|
|
|
|
It is up to the handler to determine this, and then do an INSERT or UPDATE |
934
|
|
|
|
|
|
|
operation as appropriate. This operation is not expected to fail, but if it |
935
|
|
|
|
|
|
|
does fail the handler should force a 4xx or 5xx status code (and provide an |
936
|
|
|
|
|
|
|
explanation) by calling C<< $self->mrest_declare_status >>. |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
If the request causes a new object - and, hence, a new resource - to be |
939
|
|
|
|
|
|
|
created, the handler should cause a C<Location> header with the URI of the |
940
|
|
|
|
|
|
|
new resource to be added to the response. This tells L<Web::Machine> to |
941
|
|
|
|
|
|
|
set the response status to C<201 Created>. |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
If the request only modifies an existing object/resource, simply do not |
944
|
|
|
|
|
|
|
add a C<Location> header to the response. This will cause L<Web::Machine> |
945
|
|
|
|
|
|
|
to return a C<200 OK> status in the response. |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=head4 C<DELETE> |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
For C<DELETE>, two methods are called: C<delete_resource> and |
951
|
|
|
|
|
|
|
C<delete_completed>. The C<delete_resource> method should enact the delete |
952
|
|
|
|
|
|
|
operation and generate the response entity. The second method, C<delete_completed>, |
953
|
|
|
|
|
|
|
is for cases when the delete operation cannot be guaranteed to have completed - |
954
|
|
|
|
|
|
|
this method defaults to false, but if it returns true L<Web::Machine> will |
955
|
|
|
|
|
|
|
trigger a C<...> response. |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=head3 Resource does not exist |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=head4 C<GET> |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
Request goes to finalization with 404 status. |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
=head4 C<POST> |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
Request goes to C<allow_missing_post>, which always returns false in |
967
|
|
|
|
|
|
|
L<Web::MREST>'s implementation. |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
After that, the request goes to finalization with 404 status. |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
If the |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=head4 C<PUT> |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=head2 C<finish_request> |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
The previous sections should suffice for the reader to gain a degree of |
980
|
|
|
|
|
|
|
understanding of how the state machine works for various types of requests, and |
981
|
|
|
|
|
|
|
how L<Web::MREST> interfaces with the response handlers. |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
The last cog of the FSM is C<finish_request>. |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
=head1 IN-DEPTH DISCUSSIONS OF VARIOUS TOPICS |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=head2 Resource definitions |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
As we read in the "crash course" above, resources are central to what a REST |
992
|
|
|
|
|
|
|
server is and does: the server processes incoming requests. Each request has |
993
|
|
|
|
|
|
|
a URI which resolves (or does not resolve) to a resource. Resources are |
994
|
|
|
|
|
|
|
defined as module variables: each module that contains resource handlers |
995
|
|
|
|
|
|
|
should also define a module variable (via C<our $resource_defs = { ... };>) |
996
|
|
|
|
|
|
|
containing the definitions of the resources covered by that module. |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
The top-level dispatch module, L<Web::MREST::Dispatch>, should implement |
999
|
|
|
|
|
|
|
a method called C<init_router> which calls the function |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
Web::MREST::InitRouter::load_resource_defs |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
for all the resource-defining modules. When the first HTTP request comes in, |
1004
|
|
|
|
|
|
|
L<Web::MREST::Resource> calls the C<init_router> method. This only happens |
1005
|
|
|
|
|
|
|
once, ensuring that the resource definitions are fully loaded for the first - |
1006
|
|
|
|
|
|
|
and all subsequent - requests. |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
Each resource definition is a hashref consisting of a number of properties. |
1009
|
|
|
|
|
|
|
This definition hashref is itself included in the C<$resources> package |
1010
|
|
|
|
|
|
|
hashref, which essentially looks like this: |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
{ |
1013
|
|
|
|
|
|
|
RESOURCE_NAME => RESOURCE_DEFINTION, |
1014
|
|
|
|
|
|
|
RESOURCE_NAME => RESOURCE_DEFINTION, |
1015
|
|
|
|
|
|
|
RESOURCE_NAME => RESOURCE_DEFINTION, |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
where C<RESOURCE_NAME> is a resource name (a string like C<'/'> or |
1019
|
|
|
|
|
|
|
C<'docu/text'>) and C<RESOURCE_DEFINITION> is that resource's definition |
1020
|
|
|
|
|
|
|
hashref. |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
The root resource should be defined under the name C<'/'> and top-level |
1023
|
|
|
|
|
|
|
resources should have a C<parent> property set to this string. |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
In the resource definition, properties can be specified either as a |
1026
|
|
|
|
|
|
|
scalar value, in which case the definition applies to all the methods |
1027
|
|
|
|
|
|
|
specified in C<< $site->MREST_SUPPORTED_HTTP_METHODS >>, or as a |
1028
|
|
|
|
|
|
|
hashref in case the given resource is only defined for certain methods. |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
In the latter case, it is not necessary to define all properties as |
1031
|
|
|
|
|
|
|
hashrefs. The set of permitted methods will always be taken from the |
1032
|
|
|
|
|
|
|
'handler' property. For example in this snippet whizzo_resource is only |
1033
|
|
|
|
|
|
|
defined for the GET method, and that will be applied to 'foo' (and the |
1034
|
|
|
|
|
|
|
rest of this resource's properties) as well. |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
'whizzo_resource' => { |
1037
|
|
|
|
|
|
|
'handler' => { |
1038
|
|
|
|
|
|
|
'GET' => 'some_method', |
1039
|
|
|
|
|
|
|
}, |
1040
|
|
|
|
|
|
|
'foo' => 'barbazbat', |
1041
|
|
|
|
|
|
|
... |
1042
|
|
|
|
|
|
|
} |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
So 'foo' will only be defined for the GET method. |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
Examples: |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
'foo_prop' => 'value applied to all available methods', |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
'bar_prop' => { |
1051
|
|
|
|
|
|
|
'GET' => 'value applied to GET requests', |
1052
|
|
|
|
|
|
|
'POST' => 'value applied to POST requests', |
1053
|
|
|
|
|
|
|
}, |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
There is one required property, 'handler', which is used to specify the |
1056
|
|
|
|
|
|
|
handler(s) for the resource (see the examples below). The value of this |
1057
|
|
|
|
|
|
|
property is taken to be the name of a method. This method call looks |
1058
|
|
|
|
|
|
|
like this: |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
$self->$handler |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
and is located in Web::MREST::Resource->resource_exists |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
(The inheritance chain is set up in C<bin/mrest> - the server startup script - |
1065
|
|
|
|
|
|
|
and via C<use parent> statements in the various modules that make up the |
1066
|
|
|
|
|
|
|
inheritance chain.) |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
In addition, each resource may have any properties you, the application |
1069
|
|
|
|
|
|
|
developer, wish to invest in it. For our 'docu' methods we use the |
1070
|
|
|
|
|
|
|
properties 'description' and 'documentation', for example. |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
Two properties - 'parent' and 'validations' - are |
1073
|
|
|
|
|
|
|
exceptions to the above and should never be defined on a per-method |
1074
|
|
|
|
|
|
|
basis: |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
- 'validations' contains validation checks to be applied when matching |
1077
|
|
|
|
|
|
|
URI to resource (for more information, see the Path::Router |
1078
|
|
|
|
|
|
|
documentation). |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
- 'parent' contains the name of the resource's parent resource |
1081
|
|
|
|
|
|
|
(defaults to '' - the root resource) |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
- 'documentation' is reserved for the self-documentation feature |
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=head3 C<Path::Router> object initialization |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
When the server starts, the C<MREST_RESOURCE_DEFINITIONS> and |
1090
|
|
|
|
|
|
|
C<MREST_ROOT_RESOURCE> meta parameters are initialized from the configuration |
1091
|
|
|
|
|
|
|
file C<config/dispatch_MetaConfig.pm> in the L<Web::MREST> distribution. |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
The application developer will of course want to define her own set of |
1094
|
|
|
|
|
|
|
resources. This should be done by manipulating the meta parameters |
1095
|
|
|
|
|
|
|
C<MREST_RESOURCE_DEFINITIONS> and C<MREST_ROOT_RESOURCE>. A good place |
1096
|
|
|
|
|
|
|
to do this is in the application's C<mrest_init_router> routine. |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
Here are two approaches to defining the application's resources, depending on |
1099
|
|
|
|
|
|
|
whether the application wishes to retain the L<Web::MREST> resources. |
1100
|
|
|
|
|
|
|
|
1101
|
|
|
|
|
|
|
=over |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
=item 1. retain |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
package MyApp::Resource; |
1106
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
use Clone 'clone'; |
1108
|
|
|
|
|
|
|
use parent 'Web::MREST::Resource'; |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
# We assume that the application somehow loads its resource definitions |
1111
|
|
|
|
|
|
|
# (including the root resource) into a package variable $r_defs -- for |
1112
|
|
|
|
|
|
|
# example by hard-coding them like this |
1113
|
|
|
|
|
|
|
my $r_defs = { ... }; |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
# ---------------------------------------- |
1116
|
|
|
|
|
|
|
# mrest_init_router - called by Web::MREST |
1117
|
|
|
|
|
|
|
# ---------------------------------------- |
1118
|
|
|
|
|
|
|
sub mrest_init_router { |
1119
|
|
|
|
|
|
|
my $self = shift; |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
# set up the root resource |
1122
|
|
|
|
|
|
|
$meta->set( 'MREST_ROOT_RESOURCE', $r_defs->{''} ); |
1123
|
|
|
|
|
|
|
delete $r_defs->{''}; |
1124
|
|
|
|
|
|
|
|
1125
|
|
|
|
|
|
|
# set up the remaining resources, retaining (but possibly |
1126
|
|
|
|
|
|
|
# overwriting) the Web::MREST default resources |
1127
|
|
|
|
|
|
|
my $mrest_defs = clone( $meta->MREST_RESOURCE_DEFINITIONS ); |
1128
|
|
|
|
|
|
|
foreach my $r_name ( keys %$r_defs ) { |
1129
|
|
|
|
|
|
|
$mrest_defs->{$r_name} = $r_defs->{$r_name}; |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
$meta->set( 'MREST_RESOURCE_DEFINITIONS', $mrest_defs ); |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
=item 2. do not retain |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
This approach is more simple because no C<mrest_init_router> need be written. |
1137
|
|
|
|
|
|
|
The application should have its own distro sharedir C<config/> and therein a |
1138
|
|
|
|
|
|
|
file C<dispatch_MetaConfig.pm>. Inside that file, the application puts its own |
1139
|
|
|
|
|
|
|
resource definitions in the C<MREST_RESOURCE_DEFINITIONS> and |
1140
|
|
|
|
|
|
|
C<MREST_ROOT_RESOURCE> parameters (refer to C<config/dispatch_MetaConfig.pm> in |
1141
|
|
|
|
|
|
|
the L<Web::MREST> distribution for syntax and semantics). |
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
The application's definitions will overlay (i.e. replace) those of |
1144
|
|
|
|
|
|
|
L<Web::MREST>. Even in this scenario, some or all of L<Web::MREST>'s resources |
1145
|
|
|
|
|
|
|
could be used in the application, but only by copy-pasting the definitions and |
1146
|
|
|
|
|
|
|
their respective handlers into the application's source code. |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
=back |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
=head3 Tree structure |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
L<Web::MFILE> allows resources to be defined in a tree structure. It is |
1154
|
|
|
|
|
|
|
designed to allow a tree structure to be described in a flat configuration |
1155
|
|
|
|
|
|
|
file. The C<MREST_RESOURCE_DEFINITIONS> hash is keyed on the resource name. |
1156
|
|
|
|
|
|
|
Child resources are indicated by including a C<parent> property with the name |
1157
|
|
|
|
|
|
|
of the parent resource. Care should be exercised not to introduce any circular |
1158
|
|
|
|
|
|
|
references. |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
If a flat structure is desired, simply do not include any C<parent> properties |
1161
|
|
|
|
|
|
|
in your resource definitions. |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
The format of C<MREST_RESOURCE_DEFINITIONS> hash is documented in |
1164
|
|
|
|
|
|
|
C<config/dispatch_MetaConfig.pm>. |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
=head3 C<< $Web::MREST::InitRouter::resources >> |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
The resource definition hashrefs in the dispatch modules are designed to be |
1170
|
|
|
|
|
|
|
written and maintained by humans. When the C<init_router> method runs, it loops |
1171
|
|
|
|
|
|
|
over all the resource definitions and builds up a second hash, |
1172
|
|
|
|
|
|
|
C<< $Web::MREST::InitRouter::resources >>, which contains the same information |
1173
|
|
|
|
|
|
|
in a format that is more convenient for automated processing. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
Since the resource definitions are a potential source of typographical and |
1176
|
|
|
|
|
|
|
semantic errors, you should dump this package variable to the log and examine |
1177
|
|
|
|
|
|
|
it to make sure your resource definitions are being processed correctly. |
1178
|
|
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=head2 Errors |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
As we move through the state machine (i.e. the chain of method calls driven |
1183
|
|
|
|
|
|
|
by L<Web::Machine>), we build up a "context" from which we generate the HTTP |
1184
|
|
|
|
|
|
|
response. Stated very simply, the response code can either be 'OK' (200) or |
1185
|
|
|
|
|
|
|
"something else" - i.e., an error of some kind. |
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
And, indeed, checking for errors accounts for a large portion of what our |
1188
|
|
|
|
|
|
|
resource modules do. As RFC2616 explains, errors can be divided into two |
1189
|
|
|
|
|
|
|
brought classes: client errors and server errors. |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
=over |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
=item Client errors (4xx) |
1194
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
Client errors have status codes that start with 4 (e.g. 400, 401, 404). |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
RFC2616 has this to say about them: |
1198
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
The 4xx class of status code is intended for cases in which the client |
1200
|
|
|
|
|
|
|
seems to have erred. Except when responding to a HEAD request, the server |
1201
|
|
|
|
|
|
|
SHOULD include an entity containing an explanation of the error situation, and |
1202
|
|
|
|
|
|
|
whether it is a temporary or permanent condition. These status codes are |
1203
|
|
|
|
|
|
|
applicable to any request method. User agents SHOULD display any included |
1204
|
|
|
|
|
|
|
entity to the user. |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
=item Server errors (5xx) |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
Server errors have codes beginning with th digit "5". According to RFC2616, |
1209
|
|
|
|
|
|
|
they |
1210
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
indicate cases in which the server is aware that it has erred or is |
1212
|
|
|
|
|
|
|
incapable of performing the request. Except when responding to a HEAD |
1213
|
|
|
|
|
|
|
request, the server SHOULD include an entity containing an explanation of |
1214
|
|
|
|
|
|
|
the error situation, and whether it is a temporary or permanent condition. |
1215
|
|
|
|
|
|
|
User agents SHOULD display any included entity to the user. These response |
1216
|
|
|
|
|
|
|
codes are applicable to any request method. |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
=back |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
The key point here is that it is not sufficient to return a bare 4xx or 5xx |
1221
|
|
|
|
|
|
|
response status code. The response should include an entity body with an |
1222
|
|
|
|
|
|
|
explanation of the error condition. |
1223
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
=head3 How to provide explanation in response entity |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
L<Web::MREST> provides a mechanism for adding the explanation to the entity |
1227
|
|
|
|
|
|
|
body as called for by RFC2616. At the exact place in your resource module |
1228
|
|
|
|
|
|
|
where you discover the error, do something like this: |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
$self->mrest_declare_status( code => '400', explanation => 'You messed up' ); |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
This will be converted into the respective L<App::CELL::Status> object and |
1233
|
|
|
|
|
|
|
returned in the response entity. The object will have properties like this: |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
{ |
1236
|
|
|
|
|
|
|
level => 'ERR', |
1237
|
|
|
|
|
|
|
code => 'You messed up', |
1238
|
|
|
|
|
|
|
payload => { |
1239
|
|
|
|
|
|
|
http_code => '500', |
1240
|
|
|
|
|
|
|
uri_path => ... (taken from the context), |
1241
|
|
|
|
|
|
|
resource_name => ... (taken from the context), |
1242
|
|
|
|
|
|
|
found_in => ... (taken from 'caller'), |
1243
|
|
|
|
|
|
|
permanent => JSON::true (the default), |
1244
|
|
|
|
|
|
|
}, |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
Alternatively, you can pass in your own arbitary L<App::CELL::Status> object. |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
To see how the L<App::CELL::Status> object becomes the response entity, see |
1250
|
|
|
|
|
|
|
the C<finish_request> method in L<Web::MREST::Resource>. |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
=head2 Context |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
Typically referred to as C<$context>, the "MREST context" is a hashref that is |
1256
|
|
|
|
|
|
|
built up during the course of request processing. In addition to being used |
1257
|
|
|
|
|
|
|
within L<Web::MREST::Resource>, it is always sent as an argument whenever |
1258
|
|
|
|
|
|
|
L<Web::MREST::Resource> calls a hook, so the developer can modify it in her |
1259
|
|
|
|
|
|
|
implementations of the various hook routines. |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=head2 Authentication |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
Ever since the Big Bad Wolf ate Granny, authentication mechanisms have been |
1265
|
|
|
|
|
|
|
prone to abuse by individuals who are willing to lie about their identity. |
1266
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
Humans are good at distinguishing one human from another, provided they can |
1268
|
|
|
|
|
|
|
apply all their senses to the task. Computers lack proper senses and are |
1269
|
|
|
|
|
|
|
downright awful at this task. Computerized authentication schemes typically |
1270
|
|
|
|
|
|
|
operate by presenting the user with one or more hoops to jump through. Whoever |
1271
|
|
|
|
|
|
|
succeeds at this task is deemed to be the user. What could go wrong? |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
Passwords (or passphrases) are the "hoop" most frequently used to authenticate |
1274
|
|
|
|
|
|
|
users and keep would-be intruders out. Therefore, a system's security is often |
1275
|
|
|
|
|
|
|
gauged by how well it protects user credentials from disclosure. Since |
1276
|
|
|
|
|
|
|
usernames are public, the only thing keeping a determined intruder at bay are |
1277
|
|
|
|
|
|
|
the passwords, and various measures are taken to protect them. |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
From the perspective of L<Web::Machine>, authentication is a matter of |
1280
|
|
|
|
|
|
|
calling the L<is_authorized> method. If the return value is false, the response |
1281
|
|
|
|
|
|
|
will be C<401 Unauthorized>. If it is true, request processing continues. |
1282
|
|
|
|
|
|
|
Whatever authentication measures the application developer decides to implement |
1283
|
|
|
|
|
|
|
should be triggered by this method call. |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
For more about L<is_authorized>, see the L<Web::Machine::Resource documentation|https://metacpan.org/pod/Web::Machine::Resource#is_authorized-authorization_header> |
1286
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
=head2 Authorization |
1290
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
Once authentication has determined the user's identity, a related task, |
1292
|
|
|
|
|
|
|
authorization, begins. As the name would imply (and the RFC's vague |
1293
|
|
|
|
|
|
|
use of the term "authorization" notwithstanding), authorization answers |
1294
|
|
|
|
|
|
|
the question: |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
Is this specific user authorized to make this request? |
1297
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
Compare this with authentication, which answers a different question: |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
Is this user really who they are purporting to be? |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
Or, even more pithily: |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
Who is this user? |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
Authorization implies a boolean "function" (in both the mathematical and |
1307
|
|
|
|
|
|
|
computer science sense) that takes three arguments: the username, the HTTP |
1308
|
|
|
|
|
|
|
method, and the resource. Implementation of this function is left to the |
1309
|
|
|
|
|
|
|
application developer. |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
It is worth noting here that L<Web::Machine> provides a C<forbidden> method. |
1312
|
|
|
|
|
|
|
Since C<is_authorized> is already taken for authentication, we can use |
1313
|
|
|
|
|
|
|
C<forbidden> for authorization. Just be sure to understand thoroughly that |
1314
|
|
|
|
|
|
|
a true return value from C<forbidden> means "not authorized". |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
=head2 Customized URI parsing |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
While L<Web::MREST> provides for URI parsing using L<Path::Router>, if this is |
1320
|
|
|
|
|
|
|
not desired the application developer can parse URIs herself by simply |
1321
|
|
|
|
|
|
|
substituting her own C<init_router> and C<match> methods for the ones provided |
1322
|
|
|
|
|
|
|
by L<Path::Router> and L<Path::Router::Route::Match>, respectively. |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
When request processing enters C<resource_exists>, |
1325
|
|
|
|
|
|
|
Alternatively, the application developer can overlay the C<init_router> routine |
1326
|
|
|
|
|
|
|
with one that returns an arbitrary object (stored in C<$router>) that has a |
1327
|
|
|
|
|
|
|
C<match> method. After that, L<Web::MREST> does |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
my $match = $router->match( $path ); |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
where C<$path> is the relative portion of the URI (i.e. everything left after |
1332
|
|
|
|
|
|
|
the C<http://myapp.example.com/> part is cut off). |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
The C<$match> object should provide a C<route> method, which should return the |
1335
|
|
|
|
|
|
|
definition of the matched resource. See L<"RESOURCE DEFINITIONS">. |
1336
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=head1 FUNCTIONS IN THIS MODULE |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
=head2 init |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
Do initialization-like things, such as loading configuration parameters. |
1343
|
|
|
|
|
|
|
Takes a PARAMHASH which can contain one of the following: |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
=over |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
=item C<distro> |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
The name of the application distribution from which the distro sharedir will be |
1350
|
|
|
|
|
|
|
loaded. |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
=item C<path> |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
The name (full path) of a directory containing the application's configuration |
1355
|
|
|
|
|
|
|
files. |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=item C<hashref> |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
A reference to a hash containing meta parameters to be loaded. |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
=back |
1362
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
=cut |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
my %ARGS = validate( @_, { |
1366
|
|
|
|
|
|
|
distro => { type => SCALAR, optional => 1 }, |
1367
|
22
|
|
|
22
|
1
|
1265
|
sitedir => { type => SCALAR, optional => 1 }, |
1368
|
|
|
|
|
|
|
hashref => { type => HASHREF, optional => 1 }, |
1369
|
|
|
|
|
|
|
early_debug => { type => SCALAR, optional => 1 }, |
1370
|
|
|
|
|
|
|
} ); |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
my $tf = $ARGS{'early_debug'}; |
1373
|
|
|
|
|
|
|
if ( $tf ) { |
1374
|
22
|
|
|
|
|
108
|
_touch $tf; |
1375
|
22
|
50
|
|
|
|
80
|
if ( -r $tf and -w $tf ) { |
1376
|
0
|
|
|
|
|
0
|
unlink $tf; |
1377
|
0
|
0
|
0
|
|
|
0
|
Log::Any::Adapter->set( 'File', $tf ); |
1378
|
0
|
|
|
|
|
0
|
$log->debug( __PACKAGE__ . "::init activating early debug logging to $tf" ); |
1379
|
0
|
|
|
|
|
0
|
} else { |
1380
|
0
|
|
|
|
|
0
|
print "Given unreadable/unwritable early debugging filespec $tf\n"; |
1381
|
|
|
|
|
|
|
} |
1382
|
0
|
|
|
|
|
0
|
} |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
# always load Web::MREST's configuration parameters |
1385
|
|
|
|
|
|
|
my $target = File::ShareDir::dist_dir('Web-MREST'); |
1386
|
|
|
|
|
|
|
$log->debug( "About to load Web::MREST configuration parameters from $target" ); |
1387
|
22
|
|
|
|
|
107
|
my $status = $CELL->load( sitedir => $target, verbose => 1 ); |
1388
|
22
|
|
|
|
|
2675
|
return $status if $status->not_ok; |
1389
|
22
|
|
|
|
|
3879
|
|
1390
|
22
|
50
|
|
|
|
68854
|
$meta->set( 'MREST_EARLY_DEBUGGING', $tf ); |
1391
|
|
|
|
|
|
|
|
1392
|
22
|
|
|
|
|
309
|
# if argument provided, load that, too |
1393
|
|
|
|
|
|
|
if ( %ARGS ) { |
1394
|
|
|
|
|
|
|
$target = undef; |
1395
|
22
|
50
|
|
|
|
1235
|
if ( $ARGS{'distro'} and $ARGS{'distro'} ne 'Web-MREST' ) { |
1396
|
0
|
|
|
|
|
0
|
# distro must be given as "MyApp-Foo", not "MyApp::Foo" |
1397
|
0
|
0
|
0
|
|
|
0
|
$target = File::ShareDir::dist_dir( $ARGS{'distro'} ); |
1398
|
|
|
|
|
|
|
$status = $CELL->load( sitedir => $target ); |
1399
|
0
|
|
|
|
|
0
|
return $status if $status->not_ok; |
1400
|
0
|
|
|
|
|
0
|
} |
1401
|
0
|
0
|
|
|
|
0
|
if ( my $sitedir_target = $ARGS{'sitedir'} ) { |
1402
|
|
|
|
|
|
|
if ( -d $sitedir_target ) { |
1403
|
0
|
0
|
|
|
|
0
|
$status = $CELL->load( sitedir => $sitedir_target ); |
1404
|
0
|
0
|
|
|
|
0
|
return $status if $status->not_ok; |
1405
|
0
|
|
|
|
|
0
|
} else { |
1406
|
0
|
0
|
|
|
|
0
|
$log->warn( 'Web::MREST::init() says sitedir argument given, but it is not a directory: ' . |
1407
|
|
|
|
|
|
|
Dumper( $sitedir_target ) ); |
1408
|
0
|
|
|
|
|
0
|
} |
1409
|
|
|
|
|
|
|
} |
1410
|
|
|
|
|
|
|
if ( $ARGS{'hashref'} ) { |
1411
|
|
|
|
|
|
|
my $count = 0; |
1412
|
0
|
0
|
|
|
|
0
|
foreach my $key ( keys %{ $ARGS{'hashref'} } ) { |
1413
|
0
|
|
|
|
|
0
|
$meta->set( $key, $ARGS{'hashref'}->{$key} ); |
1414
|
0
|
|
|
|
|
0
|
$count += 1; |
|
0
|
|
|
|
|
0
|
|
1415
|
0
|
|
|
|
|
0
|
} |
1416
|
0
|
|
|
|
|
0
|
$log->notice( "Web::MREST::init loaded $count meta parameters from a hashref" ); |
1417
|
|
|
|
|
|
|
} |
1418
|
0
|
|
|
|
|
0
|
} |
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
return $CELL->status_ok; |
1421
|
|
|
|
|
|
|
} |
1422
|
22
|
|
|
|
|
114
|
|
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
=head2 version |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
Accessor method (to be called like a constructor) providing access to C<$VERSION> variable |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
=cut |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
1; |