.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Web::MREST 3pm" .TH Web::MREST 3pm "2022-09-21" "perl v5.34.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Web::MREST \- Minimalistic REST server .SH "VERSION" .IX Header "VERSION" Version 0.290 .SS "Development status" .IX Subsection "Development status" Web::MREST is currently in \*(L"Alpha \- feature freeze\*(R". There are almost certainly bugs lurking in the code, but all features have been implemented. .SH "SYNOPSIS" .IX Header "SYNOPSIS" To take this module for a spin, execute this command: .PP .Vb 1 \& $ mrest\-standalone .Ve .PP Leave this running, and from another console start the command-line client: .PP .Vb 1 \& $ mrest\-cli .Ve .PP In the \s-1CLI\s0 client, type e.g. .PP .Vb 1 \& Web::MREST::CLI::Parser> get / .Ve .PP A '\s-1GET\s0' request will be sent for the root resource and the \s-1CLI\s0 client will display a representation of the response. .PP A similar result can be obtained using \f(CW\*(C`curl\*(C'\fR: .PP .Vb 1 \& curl \-v http://localhost:5000/ \-X GET \-H "Content\-Type: application/json" .Ve .PP For more information on using the \s-1CLI\s0 client, see Web::MREST::CLI. .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\s-1MREST\s0 stands for \*(L"minimalistic\*(R" or \*(L"mechanical\*(R" \s-1REST\s0 server. (Mechanical because it relies on Web::Machine.) .PP Web::MREST provides a fully functional \s-1REST\s0 server that can be started with a simple command. Without modification, the server provides a set of generalized resources that can be used to demonstrate how the \s-1REST\s0 server works, or for testing. .PP Developers can use Web::MREST as a platform for implementing their own \&\s-1REST\s0 servers, as described below. App::Dochazka::REST is a \*(L"real-world\*(R" example of such a server. .PP For an introduction to \s-1REST\s0 and Web Services, see Web::MREST::WebServicesIntro. .SH "RFC2616 AS A STATE MACHINE" .IX Header "RFC2616 AS A STATE MACHINE" \&\s-1RFC2616\s0 is, of course, the \s-1HTTP 1.1\s0 standard \- not a state machine. But the authors of \*(L"Web Machine\*(R" (which was originally implemented in Erlang) had a neat idea to represent it as a state machine and use this to implement a server for providing web services. .PP Web::Machine is, of course, the Perl port of Web Machine. .PP Web::MREST relies on Web::Machine to implement \s-1RFC2616.\s0 Web::MREST can be thought of as an additional abstraction layer over Web::Machine. .PP By itself, Web::Machine is not a server. It does not listen on a port, for example. Instead, it is designed to work (via Plack) with a \&\s-1PSGI\s0\-compliant web server. .PP The web server hands incoming requests over to Web::Machine, which runs the requests through its state machine. (The Web::Machine authors refer to the state machine as \*(L"the \s-1FSM.\*(R"\s0) The best way to grasp the state machine is to envision it as a flow-chart. At each \*(L"decision node\*(R" of the flow-chart \- where flow can go in one of two directions \- Web::Machine calls the method corresponding to that node. Each node is designated by a letter and a number: e.g. F7, O18, etc. .PP The flow-chart implemented by the \s-1FSM\s0 can be found here \- you are encouraged to have that open for reference while reading this documentation and implementing your \s-1REST\s0 server. .SH "SERVER STARTUP AND INHERITANCE SCHEME" .IX Header "SERVER STARTUP AND INHERITANCE SCHEME" .SS "Standalone mode" .IX Subsection "Standalone mode" As stated above, Web::MREST is capable of operating independently. To try it out, start up the server like this: .PP .Vb 1 \& $ mrest\-standalone .Ve .PP And then point your browser to .PP .Vb 1 \& http://localhost:5000 .Ve .PP If you look inside the \f(CW\*(C`mrest\-standlone\*(C'\fR script, you will see that it is just a wrapper for the \f(CW\*(C`mrest\*(C'\fR script, which takes two mandatory options. The first, \f(CW\*(C`\-\-distro\*(C'\fR, is the name of the distribution in whose sharedir it should look for configuration files. The second, \f(CW\*(C`\-\-module\*(C'\fR, is the name of the application's resource module, i.e. the ultimate module in the chain of inheritance. .PP In standalone mode, the actual command that is run is: .PP .Vb 1 \& mrest \-\-distro=Web::MREST \-\-module=Web::MREST::Dispatch .Ve .PP which causes the chain of inheritance to be built up as follows: .ie n .IP """bin/mrest""" 4 .el .IP "\f(CWbin/mrest\fR" 4 .IX Item "bin/mrest" calls \f(CW\*(C`Web::Machine\->new\*(C'\fR; the Web::Machine object is blessed into Web::MREST::Dispatch .IP "Web::MREST::Dispatch" 4 .IX Item "Web::MREST::Dispatch" inherits from Web::MREST::Entity .IP "Web::MREST::Entity" 4 .IX Item "Web::MREST::Entity" inherits from Web::MREST::Resource .IP "Web::MREST::Resource" 4 .IX Item "Web::MREST::Resource" inherits from Web::Machine::Resource .PP When you browse to \f(CW\*(C`http://0:5000\*(C'\fR in standalone mode, you get a list of the sample \s-1REST\s0 resources that are available. For more information on these, see \&\f(CW\*(C`config/dispatch_Config.pm\*(C'\fR. .SS "With your application" .IX Subsection "With your application" Starting the server with your application is the same as described in \&\*(L"Standalone mode\*(R", above, except that you replace \f(CW\*(C`Web\-MREST\*(C'\fR with the name of your distribution and \f(CW\*(C`Web::MREST::Dispatch\*(C'\fR with the name of your ultimate resource module. .PP .Vb 1 \& $ mrest YourApp\-MREST YourApp::MREST::Dispatch .Ve .PP For example, here we are starting the server with the distribution \&\f(CW\*(C`YourApp\-MREST\*(C'\fR, which is presumed to implement a chain of inheritance similar to Web::MREST's, i.e.: .PP .Vb 1 \& Web::MREST \-> YourApp::MREST::Resource \-> YourApp::MREST::Dispatch .Ve .PP Thanks to this arrangement, the application developer can customize Web::MREST \- i.e., not only providing her own resources and handlers, but even altering how the state machine operates, if necessary \- by providing her own chain of inheritance and overriding various methods within it. .PP \fIRecapitulation\fR .IX Subsection "Recapitulation" .PP Since the above is quite important, let's go over it again: .PP The Web::MREST documentation will always refer to your application either as the \*(L"application\*(R" or as \f(CW\*(C`YourApp\*(C'\fR. The application should take the form of a Perl distribution, which should have: .IP "\(bu" 4 a distribution sharedir .IP "\(bu" 4 a resource module, \f(CW\*(C`YourApp::Resource\*(C'\fR. .IP "\(bu" 4 a dispatch module, \f(CW\*(C`YourApp::Dispatch\*(C'\fR .PP For now, just think of these three components as \*(L"black boxes\*(R". We will cover their contents later. .PP The server (i.e. your application), is started by executing the \f(CW\*(C`mrest\*(C'\fR executable with the name of your application's distribution and the name of its dispatch module, which should be the ultimate module in the chain of inheritance. .PP .Vb 1 \& $ mrest \-\-distro YourApp \-\-module YourApp::Dispatch .Ve .PP Under the hood the startup script, which can be reviewed at \f(CW\*(C`bin/mrest\*(C'\fR, does essentially this: .PP .Vb 1 \& use Web::Machine; \& \& Web::Machine\->new( \& resource => \*(AqYourApp::Dispatch\*(Aq, \& )\->to_app; .Ve .PP There are two key points concerning the Web::Machine object constructed by call to \f(CW\*(C`Web::Machine\->new\*(C'\fR: .ie n .IP "1. the object is blessed into ""YourApp::Dispatch""" 4 .el .IP "1. the object is blessed into \f(CWYourApp::Dispatch\fR" 4 .IX Item "1. the object is blessed into YourApp::Dispatch" .PD 0 .IP "2. the object is a Plack application" 4 .IX Item "2. the object is a Plack application" .PD .SH "INHERITANCE SCHEME" .IX Header "INHERITANCE SCHEME" As seen in the previous section, \f(CW\*(C`YourApp\*(C'\fR inherits from Web::MREST via a chain of inheritance. Here is the chain implemented by Web::MREST: .PP .Vb 5 \& \-> Web::MREST::Dispatch \& \-> Web::MREST::Entity \& \-> Web::MREST::Resource \& \-> Web::Machine::Resource \& \-> Plack::Component .Ve .PP Assuming YourApp has its authentication and authorization routines in YourApp::Resource and its resource definitions and handlers in YourApp::Dispatch, the chain for YourApp would look like this: .PP .Vb 6 \& \-> YourApp::Dispatch \& \-> YourApp::Resource \& \-> Web::MREST::Entity \& \-> Web::MREST::Resource \& \-> Web::Machine::Resource \& \-> Plack::Component .Ve .PP (In other words, YourApp::Dispatch and YourApp::Resource replace Web::MREST::Dispatch, which is just a demo.) .PP When Web::Machine reaches a given node in the \s-1FSM,\s0 it calls the corresponding method on that Web::Machine object. Since the object is blessed into \f(CW\*(C`YourApp::Dispatch\*(C'\fR, that module is where Perl will start to look for the method. .PP If the method is not found at the lowest level, Perl follows the chain of inheritance \*(L"upward\*(R". The highest level, Plack::Component, is shown only for completeness \- Web::MREST::Resource and Web::MREST::Entity implement all the methods that your resource module might (or should) want to override. .PP Readers who are not well-versed in writing Perl applications that use inheritance are referred to the fine Perl manuals such as \f(CW\*(C`perlootut\*(C'\fR. .SH "STATE MACHINE INTRODUCTION" .IX Header "STATE MACHINE INTRODUCTION" At this point we have enough background information to begin to grasp the state machine. (Instead of writing \*(L"state machine\*(R" we will follow the Web::Machine convention of referring to it as the \*(L"\s-1FSM\*(R".\s0) This section presents selected features and nodes of the \s-1FSM,\s0 how Web::MREST implements them, and how to use them. The discourse proceeds in the order in which the methods are called when an \s-1HTTP\s0 request enters the \s-1FSM.\s0 We can envision these method calls as decision nodes of a flow-chart, or \*(L"cogs\*(R" of the \s-1FSM.\s0 .PP And we needn't just imagine the flow-chart \- it actually exists and can be downloaded from .... If you want to understand how Web::Machine and Web::MREST work, this document is of fundamental importance. Hereinafter it will be referred to as \*(L"the \s-1FSM\s0 diagram\*(R". .PP As you can see in the \s-1FSM\s0 diagram, each \s-1FSM\s0 cog has a code like \f(CW\*(C`B6\*(C'\fR, for ease of reference. .SH "POLICIES AND FEATURES" .IX Header "POLICIES AND FEATURES" Web::Machine implements the \s-1FSM,\s0 and that's all it does. In particular, it imposes no policies on distributions that use it. By taking this approach, Web::Machine maximizes its range of potential uses. .PP Powerful as it is, Web::Machine can be confusing to use. When I started writing my first application based on it, I found myself wanting an intermediate module between my application and Web::Machine \- something that would make Web::Machine a little more friendly. .PP Web::MREST is that module. It builds on Web::Machine in an effort to provide certain additional features. Inevitably, this means imposing some policies (i.e., limitations) on users. To me that seems like an acceptable trade-off. .SS "Path dispatch" .IX Subsection "Path dispatch" A key part of any web application is \*(L"path dispatch\*(R" (i.e. \s-1URI\s0 translation), which answers the question: \*(L"how are URIs mapped to resources?\*(R" .PP Although Web::Machine provides a way to specify handlers for various media types that may appear in request and response entities, it provides no way of getting from the \s-1URI\s0 to the handler. Web::MREST bridges this gap by providing a system of resource definitions (see \*(L"Resource definitions\*(R", below). .PP The definition of each resource specifies the URI-to-resource mapping and provides the name of the resource's handler method. Internally, Web::MREST uses a single Path::Router object to parse URIs. .PP Before any URIs can be parsed, this Path::Router object must be initialized. This is done in Web::MREST::Resource, in the \f(CW\*(C`service_available\*(C'\fR method. That method checks the scalar variable that is supposed to contain the Path::Router object and, if needed, calls the \f(CW\*(C`init_router\*(C'\fR method to initialize it. .PP In the Web::MREST demo application, \f(CW\*(C`init_router\*(C'\fR is implemented in Web::MREST::Dispatch. .SS "Resource handlers" .IX Subsection "Resource handlers" The Web::Machine documentation mentions \*(L"handlers\*(R" but doesn't go into any detail on how to write them. Web::MREST not only provides some working resource handlers, but also implements a paradigm for writing them. .PP In this paradigm, the handler is called as a method, just like any of the other methods in the chain of inheritance. (To avoid namespace issues, it is recommended that handler method names start with \f(CW\*(C`handler_\*(C'\fR.) The name of the method is specified in the resource definition. .PP The handler method is called twice \- in other words, there are two passes. In the first pass, the handler is called with the argument \f(CW1\fR (scalar value) and is expected to return a boolean value indicating whether the resource exists. .PP In the second pass, indicated by the argument \f(CW2\fR (scalar value), the handler is expected to return a \f(CW\*(C`App::CELL::Status\*(C'\fR object. This object (rendered in \&\s-1JSON\s0) becomes the response entity unless overrided by a declared status (see \&\f(CW\*(C`mrest_declare_status\*(C'\fR in Web::MREST::Resource. .PP \&\fBN.B.:\fR The request entity is not available to the handler (via \&\f(CW\*(C`$self\-\*(C'\fRcontext\->{request_entity}> until the second pass! .SS "Status objects" .IX Subsection "Status objects" As mentioned in the previous section, App::CELL::Status objects are returned by resource handlers. Not only that \- Web::MREST tries its best to \fIalways\fR return an App::CELL::Status object in the response entity. .PP Actually, it is not the object itself that is returned, but a \s-1JSON\s0 representation of its underlying data structure. From this, the object can easily be reconstituted on the client side by doing .PP .Vb 2 \& my $status = $JSON\->decode( $response_entity ); \& bless $status, \*(AqApp::CELL::Status\*(Aq; .Ve .PP For more on what status objects can do, see App::CELL::Status, App::CELL, and App::CELL::Guide. .SS "Error statuses" .IX Subsection "Error statuses" Web::Machine always tries to return the proper \s-1HTTP\s0 status code in the response. The application developer will likely need to \*(L"force\*(R" a code in certain cases. For example, the request may be \*(L"malformed\*(R" in a way that is not discoverable until the handler runs. Or, caught exceptions may need to be exposed to the client with \f(CW\*(C`500 \- Internal Error\*(C'\fR. .PP Also, the \s-1RFC\s0 says .PP .Vb 2 \& . . . the server SHOULD include an entity containing an explanation of the \& error situation, and whether it is a temporary or permanent condition. .Ve .PP Clearly, then, a mechanism is needed for providing such explanations and indicating whether the error is temporary or permanent. And that mechanism should enable an arbitrary status code to be declared. .PP By itself, Web::Machine does not really provide such a mechanism. What it does provide is a mechanism for \*(L"forcing\*(R" an arbitrary status code (e.g. \f(CW\*(C`404 \&\- Not Found\*(C'\fR) by returning a scalar reference. This mechanism has two disadvantages: .IP "it is only available at certain junctions of the \s-1FSM\s0" 4 .IX Item "it is only available at certain junctions of the FSM" I wanted a way to \*(L"declare\*(R" a status code at any point and be certain that Web::Machine won't change it later on. .IP "there is no obvious way to provide an explanation of the error" 4 .IX Item "there is no obvious way to provide an explanation of the error" Web::Machine considers this an implementation detail. .PP Hence, Web::MREST provides the \f(CW\*(C`mrest_declare_status\*(C'\fR method. To learn how to call it and how it works, see Web::MREST::Resource. .SH "THE FINE STATE MACHINE" .IX Header "THE FINE STATE MACHINE" In this section we take a detailed look at the \s-1FSM\s0 by considering some common scenarios. For our purposes these are \f(CW\*(C`GET\*(C'\fR, \f(CW\*(C`POST\*(C'\fR, \f(CW\*(C`PUT\*(C'\fR, and \f(CW\*(C`DELETE\*(C'\fR requests. Handling can differ according to whether or not a \f(CW\*(C`POST\*(C'\fR creates a new resource and whether or not the resource is determined to exist. .SS "Part One (sanity checks and information gathering)" .IX Subsection "Part One (sanity checks and information gathering)" The first few cogs are executed, in the same order, on all requests regardless of method. They can be thought of both as a set of sanity checks and as an information-gathering process. .PP \fI\f(CI\*(C`service_available\*(C'\fI (B13)\fR .IX Subsection "service_available (B13)" .PP The first method call is \f(CW\*(C`service_available\*(C'\fR, which is implemented by Web::MREST::Resource and should \fInot\fR be implemented by your application, because it calls \f(CW\*(C`init_router\*(C'\fR to ensure that all the resource definitions are loaded and the Path::Router singleton is properly initialized. .PP This is not really a limitation, however. Whatever code you need to run here can be placed in a method called \f(CW\*(C`mrest_service_available\*(C'\fR, which should return a boolean value (i.e. 1 or 0), which determines the return value from the method. .PP If the service really isn't available, you can return false, which will trigger a \f(CW\*(C`503 Service Not Available\*(C'\fR response. Before returning you should do: .PP .Vb 1 \& $self\->mrest_declare_status( explanation => \*(Aq...\*(Aq, permanent => 0 ); .Ve .PP to provide an explanation of what is going on. .PP For details, see the \f(CW\*(C`t/503\-Service\-Unavailable.t\*(C'\fR unit test. .PP \fI\f(CI\*(C`known_methods\*(C'\fI (B12)\fR .IX Subsection "known_methods (B12)" .PP Returns the list of supported (\*(L"known\*(R") methods in \&\f(CW\*(C`$site\->MREST_SUPPORTED_HTTP_METHODS\*(C'\fR. If the request method is not in that list, a \f(CW\*(C`501 Not Implemented\*(C'\fR response is returned along with an explanation that the method requested is not supported. .PP If this behavior is not appropriate, the method can be implemented by the application. .PP \fI\f(CI\*(C`uri_too_long\*(C'\fI (B11)\fR .IX Subsection "uri_too_long (B11)" .PP If the request \s-1URI\s0 is longer than the value set in the \f(CW\*(C`MREST_MAX_LENGTH_URI\*(C'\fR site parameter, the client will receive a \f(CW\*(C`414 Request URI Too Long\*(C'\fR response. .PP To override this behavior, provide your own \f(CW\*(C`uri_too_long\*(C'\fR routine in your resource module. .PP This functionality is demonstrated by the \f(CW\*(C`t/414\-Request\-URI\-Too\-Long.t\*(C'\fR unit. .PP \fI\f(CI\*(C`allowed_methods\*(C'\fI (B10)\fR .IX Subsection "allowed_methods (B10)" .PP \&\*(L"Is the method allowed on this resource?\*(R" .PP This next routine is where things start to get complicated. According to the Web::Machine::Resource documentation , we are expected to respond with a list of methods allowed on the resource. To assemble such a list, we must first answer two questions: .IP "1. Have the resource definitions been loaded?" 4 .IX Item "1. Have the resource definitions been loaded?" .PD 0 .IP "2. Does the \s-1URI\s0 match a known resource?" 4 .IX Item "2. Does the URI match a known resource?" .PD .PP After the server starts, the first time this method is called triggers a call to the \f(CW\*(C`init_router\*(C'\fR method, which populates the \f(CW$resources\fR package variable in \f(CW\*(C`Web::MREST::InitRouter\*(C'\fR with all the resource definitions. This is explained in detail in \*(L"Resource definitions\*(R". This takes care of the first question. .PP The second question is answered by \f(CW\*(C`Path::Router\*(C'\fR. Once the request has been associated with a known resource, completing our task becomes a matter of getting and returning the set of methods for which the resource is defined. .PP \fI\f(CI\*(C`malformed_request\*(C'\fI (B9)\fR .IX Subsection "malformed_request (B9)" .PP A true return value from this method triggers a \*(L"400 Bad Request\*(R" response status. \s-1RFC2616\s0 does not stipulate exactly what constitutes a bad request. We already (in allowed_methods) took care of the case when the \s-1URI\s0 fails to match a known resource, and that includes applying any \f(CW\*(C`validations\*(C'\fR properties from the resource definition. .PP So, in this method (or your overlay) we take the \*(L"next step\*(R" (whatever that is) in vetting the request. Keep in mind that this method is called before the resource handler. If you have any sanity checks you wish to apply _after_ the \s-1URI\s0 is matched to a resource but _before_ the resource handler fires, this is the place to put them. .PP If you would like to keep Web::MREST's implementation of this method (which, for example, pushes the Content-Length and Content-Type information onto the context) and add your own logic, you can put it in \&\f(CW\*(C`mrest_malformed_request\*(C'\fR instead of overriding \f(CW\*(C`malformed_request\*(C'\fR itself. .PP If you intend to return false from this method you should first do this: .PP .Vb 1 \& $self\->mrest_declare_status( explanation => \*(Aq...\*(Aq ); .Ve .PP to ensure that an explanation is included with the 400 response. .PP \fI\f(CI\*(C`is_authorized\*(C'\fI (B8)\fR .IX Subsection "is_authorized (B8)" .PP In my mind, \*(L"authentication\*(R" is the process of determining who the user is, and \*(L"authorization\*(R" determines if the user is allowed to do what she is asking to do. However, \s-1RFC2616\s0 does not make such a clear distinction. .PP For that reason, it is left to the application to implement this method if needed. .PP \fI\f(CI\*(C`forbidden\*(C'\fI (B7)\fR .IX Subsection "forbidden (B7)" .PP The same thoughts as expressed under \f(CW\*(C`is_authorized\*(C'\fR, above, apply to this method as well. .PP \fI\f(CI\*(C`valid_content_headers\*(C'\fI (B6)\fR .IX Subsection "valid_content_headers (B6)" .PP This is where you vet the \f(CW\*(C`Content\-*\*(C'\fR headers in the request. If the request contains any invalid \f(CW\*(C`Content\-*\*(C'\fR headers (i.e., if the '*' part does not appear in << \f(CW$site\fR\->\s-1MREST_VALID_CONTENT_HEADERS\s0 >>), a 501 will be generated. .PP The content headers are passed to the method in a Hash::MultiValue object. .PP \fI\f(CI\*(C`known_content_type\*(C'\fI (B5)\fR .IX Subsection "known_content_type (B5)" .PP If the \f(CW\*(C`Content\-Type\*(C'\fR header is relevant \- i.e., if this is a \s-1PUT\s0 or \&\s-1POST\s0 request and if there is a request entity \- check it against << \f(CW$site\fR\->\s-1MREST_SUPPORTED_CONTENT_TYPES\s0 >>. .PP \fI\f(CI\*(C`valid_entity_length\*(C'\fI (B4)\fR .IX Subsection "valid_entity_length (B4)" .PP A simple routine that compares the entity length (in bytes) with the maximum set in \f(CW\*(C`$site\->MREST_MAX_LENGTH_REQUEST_BODY\*(C'\fR. .PP \fI\f(CI\*(C`options\*(C'\fI (B3)\fR .IX Subsection "options (B3)" .PP If your application needs to support the \f(CW\*(C`OPTIONS\*(C'\fR method, you should implement this yourself \- otherwise, ignore it. .SS "Part Two (content negotioation)" .IX Subsection "Part Two (content negotioation)" The \s-1HTTP\s0 standard provides some complicated logic to enable clients and servers to \*(L"negotiate\*(R" the format (media type), language, encoding, etc. in which content will be passed back and forth. Here in the Web::MREST documentation we gloss over this complexity and focus only on the media type. However, Web::Machine includes methods for handling all the content negotiation decision nodes and the application developer is free to take advantage of them. .PP That said, Web::MREST itself provides \s-1JSON\s0 handlers for both the request and the response entities, and should be fully \s-1UTF\-8\s0 clean. Hopefully, this will save application developers some work. (For more information, see \*(L"\s-1STATUS OBJECTS AND ERROR HANDLING\*(R"\s0.) .PP The following subsections detail the principal content negotiation methods. .PP \fI\f(CI\*(C`content_types_provided\*(C'\fI\fR .IX Subsection "content_types_provided" .PP As the Web::Machine::Resource documentation states, this method must be implemented (i.e., by the application) \- otherwise, \*(L"your resource will not be able to return any useful content\*(R". .PP Quoting further: \*(L"This should return an \s-1ARRAY\s0 of \s-1HASH\s0 ref pairs where the key is the name of the media type and the value is a \s-1CODE\s0 ref (or name of a method) which can provide a resource representation in that media type.\*(R" .PP The implementation provided by Web::MREST allows clients to specify (via an \f(CW\*(C`Accept\*(C'\fR header) one of two media types: .ie n .IP """text/html""" 4 .el .IP "\f(CWtext/html\fR" 4 .IX Item "text/html" Since it is the first hashref pair of the two, it is the default. That means if the incoming request does not have an \f(CW\*(C`Accept\*(C'\fR header, the handler specified for \f(CW\*(C`text/html\*(C'\fR will be called to generate the response entity. .ie n .IP """application/json""" 4 .el .IP "\f(CWapplication/json\fR" 4 .IX Item "application/json" This is the media type that Web::MREST was written to support, both in request entities and in response entities. However, there is nothing preventing you as the application developer from specifying handlers for other media types. .PP If the request includes an \f(CW\*(C`Accept\*(C'\fR header, but none of the media types specified in it are found in \f(CW\*(C`content_types_provided\*(C'\fR, Web::Machine will generate a \f(CW\*(C`406 Not Acceptable\*(C'\fR response. (Unfortunately, there is no easy way for Web::MREST or the application to know in advance that this error will be triggered, so it will be returned \*(L"bare\*(R" \- i.e., without any explanatory response entity.) .PP In the normal case when an acceptable handler exists, it will be called to generate the response \- in other words, whatever is returned by the chosen handler becomes the response entity, unless an error occurs inside the handler. In that case, the handler should return a reference to a scalar value (e.g., \e400), which Web::Machine will interpret as an \s-1HTTP\s0 response code. See \*(L"\s-1STATUS OBJECTS AND ERROR HANDLING\*(R"\s0. .PP For more on response entity generation, see the sections dedicated to the various \s-1HTTP\s0 methods (\*(L"\s-1GET\*(R"\s0, \*(L"\s-1PUT\*(R"\s0, \*(L"\s-1POST\*(R"\s0, \*(L"\s-1DELETE\*(R"\s0), below. .PP \fI\f(CI\*(C`content_types_accepted\*(C'\fI\fR .IX Subsection "content_types_accepted" .PP When the client sends \f(CW\*(C`PUT\*(C'\fR or \f(CW\*(C`POST\*(C'\fR requests, it will typically provide a \&'Content\-Type' header specifying the media type of the bytes it is sending in the request body. This content type is compared with the media types returned by this method. If there is no match, Web::Machine returns a \f(CW\*(C`415 Unsupported Media Type\*(C'\fR error response. (Unfortunately, there is no easy way for Web::MREST or the application to know in advance that this error will be triggered, so it will be returned \*(L"bare\*(R" \- i.e., without any explanatory response entity.) .PP \fIOther methods\fR .IX Subsection "Other methods" .PP For handling character sets, encodings, and languages, Web::Machine provides a number of other content negotiation methods: .ie n .IP """charsets_provided""" 4 .el .IP "\f(CWcharsets_provided\fR" 4 .IX Item "charsets_provided" .PD 0 .ie n .IP """default_charset""" 4 .el .IP "\f(CWdefault_charset\fR" 4 .IX Item "default_charset" .ie n .IP """languages_provided""" 4 .el .IP "\f(CWlanguages_provided\fR" 4 .IX Item "languages_provided" .ie n .IP """encodings_provided""" 4 .el .IP "\f(CWencodings_provided\fR" 4 .IX Item "encodings_provided" .ie n .IP """variances""" 4 .el .IP "\f(CWvariances\fR" 4 .IX Item "variances" .PD .PP However, they are only needed if the application does complex content negotiation. .SS "Part Three (resource existence)" .IX Subsection "Part Three (resource existence)" When we have made it past content negotiation, we know more than just which routines will be used to process the request entity (if any) and generate the response. We have gathered quite a bit of information about the request. All this information has been pushed onto the context, so it is available to all our resource methods, including the resource handler which we will get to presently. This information includes: .PP (\s-1FIXME:\s0 verify this list as it is outdated) .ie n .IP """method""" 4 .el .IP "\f(CWmethod\fR" 4 .IX Item "method" The request method .ie n .IP """resource_name""" 4 .el .IP "\f(CWresource_name\fR" 4 .IX Item "resource_name" The resource name, which can be used as a key to look up the full resource definition in the \f(CW$Web::MREST::InitRouter::resources\fR .ie n .IP """handler_name""" 4 .el .IP "\f(CWhandler_name\fR" 4 .IX Item "handler_name" The name of the resource handler, e.g. \f(CW\*(C`handler_bugreport\*(C'\fR. In Web::MREST, the resource handlers reside in the Web::MREST::Dispatch module. .ie n .IP """uri""" 4 .el .IP "\f(CWuri\fR" 4 .IX Item "uri" The full \s-1URI\s0 provided with the request .ie n .IP """uri_base""" 4 .el .IP "\f(CWuri_base\fR" 4 .IX Item "uri_base" The base part of the \s-1URI\s0 (e.g. \*(L"http://localhost:5000/\*(R" ) .ie n .IP """uri_path""" 4 .el .IP "\f(CWuri_path\fR" 4 .IX Item "uri_path" The relative path to the resource (e.g. \*(L"/bugreport\*(R") .ie n .IP """components""" 4 .el .IP "\f(CWcomponents\fR" 4 .IX Item "components" Reference to an array the elements of which are the individual 'components' (i.e., everything between the '/' characters) of the \f(CW\*(C`uri_path\*(C'\fR .ie n .IP """mapping""" 4 .el .IP "\f(CWmapping\fR" 4 .IX Item "mapping" A hashref mapping resource parameter names (if any) to their values .ie n .IP """content\-length""" 4 .el .IP "\f(CWcontent\-length\fR" 4 .IX Item "content-length" The content-length header. .ie n .IP """content\-type""" 4 .el .IP "\f(CWcontent\-type\fR" 4 .IX Item "content-type" The content-type header. .PP One major piece of information is missing, however: whether the resource exists or not. For that, we have to actually call the resource handler. .PP \fI\f(CI\*(C`resource_exists\*(C'\fI (G7)\fR .IX Subsection "resource_exists (G7)" .PP The term \*(L"resource\*(R" is not precisely defined. It can refer to the resource definition (a data structure), the resource handler (a Perl subroutine called as an object method), or an object (set of records) in an underlying database. Or it can refer to all of the above, or to something else. The following paragraphs describe Web::MREST's approach. .PP By the time control reaches this method, the request \s-1URI\s0 has already been matched to a resource definition. So the resource handler is known. Since we have no other way of knowing, we ask the resource itself, by calling the handler with the scalar value \f(CW1\fR (i.e. the numeral 1) as the sole argument. This handler call is referred to as the \*(L"first pass\*(R". .PP How the handler is implemented does not concern us. We only ask that it return a boolean value (true or false) when called with this argument. If the return value from the handler is true, we can assume that the handler will be called again (second pass) in the response generation phase \- read on. .SS "Part Four (generation of response entity)" .IX Subsection "Part Four (generation of response entity)" At this point we have .IP "gathered information about the request and placed it on the context" 4 .IX Item "gathered information about the request and placed it on the context" .PD 0 .IP "run the resource handler (first pass) to determine resource existence" 4 .IX Item "run the resource handler (first pass) to determine resource existence" .PD .PP Up until now (i.e., through determination of resource existence), the \s-1FSM\s0 has been a series of steps applied, in the same order, regardless of the \&\s-1HTTP\s0 method. .PP In the sections below, we examine how responses are generated for each of four \s-1HTTP\s0 methods (\f(CW\*(C`GET\*(C'\fR, \f(CW\*(C`PUT\*(C'\fR, \f(CW\*(C`POST\*(C'\fR, and \f(CW\*(C`DELETE\*(C'\fR) when the resource exists and when it doesn't exist. .PP \fIResource exists\fR .IX Subsection "Resource exists" .PP \f(CW\*(C`GET\*(C'\fR .IX Subsection "GET" .ie n .IP "1. ""content_types_provided"" method call" 4 .el .IP "1. \f(CWcontent_types_provided\fR method call" 4 .IX Item "1. content_types_provided method call" First, \f(CW\*(C`content_types_provided\*(C'\fR is called to determine the name of the method that is capable of generating the response in the required format. This method is the one we mean when we refer to the \*(L"response generator\*(R". .IP "2. Response generator method call" 4 .IX Item "2. Response generator method call" Second, the response generator is called (from \f(CW\*(C`o18\*(C'\fR in Web::Machine::FSM::States). It is expected to always return an App::CELL::Status object. If an error condition is detected, the handler should declare it using \f(CW\*(C`$self\->mrest_declare_status\*(C'\fR and then return a \*(L"non_ok\*(R" status. .PP \&\f(CW\*(C`GET\*(C'\fR is the only request method that demands a response entity in the format specified by the \f(CW\*(C`Accept\*(C'\fR header. For the other methods, response entities are optional, but recommended. In practice, this means that we have to create them ourselves. .PP \f(CW\*(C`POST\*(C'\fR .IX Subsection "POST" .PP Here we have two possible paths, depending on the value returned by \&\f(CW\*(C`post_is_create\*(C'\fR: .ie n .IP """post_is_create"" true" 4 .el .IP "\f(CWpost_is_create\fR true" 4 .IX Item "post_is_create true" .RS 4 .PD 0 .ie n .IP """create_path"" and ""create_path_after_handler""" 4 .el .IP "\f(CWcreate_path\fR and \f(CWcreate_path_after_handler\fR" 4 .IX Item "create_path and create_path_after_handler" .PD If, and only if, \f(CW\*(C`post_is_create\*(C'\fR is true, processing continues via \&\f(CW\*(C`create_path\*(C'\fR and \f(CW\*(C`create_path_after_handler\*(C'\fR. Depending on the value of the latter, the request handler (determined by consulting \&\f(CW\*(C`content_types_accepted\*(C'\fR) is called either before or after \f(CW\*(C`create_path\*(C'\fR. .Sp The request handler should stage the response entity in preparation for finalization. The content type can be inferred from \&\f(CW\*(C`$request\->env\->{\*(Aqweb.machine.context\*(Aq}\*(C'\fR. .IP "Finalization" 4 .IX Item "Finalization" Request is finalized by a call to \f(CW\*(C`finish_request\*(C'\fR. .RE .RS 4 .RE .ie n .IP """post_is_create"" false" 4 .el .IP "\f(CWpost_is_create\fR false" 4 .IX Item "post_is_create false" If \f(CW\*(C`post_is_create\*(C'\fR returns false, all bets are off. For reasons I do not understand, Web::Machine does not consult \f(CW\*(C`content_types_provided\*(C'\fR or \&\f(CW\*(C`content_types_accepted\*(C'\fR on this type of request. The only thing it does is call \f(CW\*(C`process_post\*(C'\fR, and so it is up to this method to do whatever needs to be done to generate an entity and get it into the response. .Sp Web::MREST helps by making sure that the content type is stored in the context (in the \f(CW\*(Aqcontent_type\*(Aq\fR property), so \f(CW\*(C`process_post\*(C'\fR can look there for it and generate the response entity accordingly. .PP \f(CW\*(C`PUT\*(C'\fR .IX Subsection "PUT" .PP On all \f(CW\*(C`PUT\*(C'\fR requests, and those \f(CW\*(C`POST\*(C'\fR requests that are handled as \&\f(CW\*(C`PUT\*(C'\fR requests (see above), Web::Machine uses the following process: .ie n .IP """content_types_accepted""" 4 .el .IP "\f(CWcontent_types_accepted\fR" 4 .IX Item "content_types_accepted" This method is called to determine the name of the method that can process the request body. This method is expected not only to process the request body, but also to generate the response. Therefore, we refer to this method as the \*(L"response generator\*(R" for \f(CW\*(C`PUT\*(C'\fR requests. .IP "Response generator method call" 4 .IX Item "Response generator method call" Next, the response generator is called. For \f(CW\*(C`PUT\*(C'\fR requests, the response generator is determined from \f(CW\*(C`content_types_accepted\*(C'\fR based on the Here again, the method referred to by \f(CW\*(C`content_types_provided\*(C'\fR is not called by Web::Machine, but the response generator is free to call \f(CW\*(C`content_types_provided\*(C'\fR and find out the method itself, and call it. Or do something else. .Sp When \f(CW\*(C`resource_exists\*(C'\fR is true, the response generator is called from \f(CW\*(C`o14\*(C'\fR in Web::Machine::FSM::States. .PP Whenever a new resource is created, a \f(CW\*(C`Location\*(C'\fR header is added to the response with the \s-1URI\s0 path of the new resource. .PP In general, we understand \f(CW\*(C`PUT\*(C'\fR to be a request to write to a resource. Typically, this will involve either creating (\s-1INSERT\s0) or modifying (\s-1UPDATE\s0) one or more database records/objects. .PP Therefore, it has to be possible for a \s-1URI\s0 to resolve to a resource that does not yet exist. For example: .PP .Vb 1 \& PUT employee/nick/Bubba .Ve .PP There may or may not be an employee by the name of Bubba in the database, but if we have a resource called 'employee/nick/:nick', Path::Router will match it in \f(CW\*(C`allowed_methods\*(C'\fR and the resource handler will be called in \&\f(CW\*(C`resource_exists\*(C'\fR \- up until this point, the same sequence of method calls is used for \f(CW\*(C`GET\*(C'\fR, \f(CW\*(C`POST\*(C'\fR, \f(CW\*(C`PUT\*(C'\fR, and \f(CW\*(C`DELETE\*(C'\fR. .PP Web::MREST has no way of knowing whether there is an employee named Bubba. It is up to the handler to determine this, and then do an \s-1INSERT\s0 or \s-1UPDATE\s0 operation as appropriate. This operation is not expected to fail, but if it does fail the handler should force a 4xx or 5xx status code (and provide an explanation) by calling \f(CW\*(C`$self\->mrest_declare_status\*(C'\fR. .PP If the request causes a new object \- and, hence, a new resource \- to be created, the handler should cause a \f(CW\*(C`Location\*(C'\fR header with the \s-1URI\s0 of the new resource to be added to the response. This tells Web::Machine to set the response status to \f(CW\*(C`201 Created\*(C'\fR. .PP If the request only modifies an existing object/resource, simply do not add a \f(CW\*(C`Location\*(C'\fR header to the response. This will cause Web::Machine to return a \f(CW\*(C`200 OK\*(C'\fR status in the response. .PP \f(CW\*(C`DELETE\*(C'\fR .IX Subsection "DELETE" .PP For \f(CW\*(C`DELETE\*(C'\fR, two methods are called: \f(CW\*(C`delete_resource\*(C'\fR and \&\f(CW\*(C`delete_completed\*(C'\fR. The \f(CW\*(C`delete_resource\*(C'\fR method should enact the delete operation and generate the response entity. The second method, \f(CW\*(C`delete_completed\*(C'\fR, is for cases when the delete operation cannot be guaranteed to have completed \- this method defaults to false, but if it returns true Web::Machine will trigger a \f(CW\*(C`...\*(C'\fR response. .PP \fIResource does not exist\fR .IX Subsection "Resource does not exist" .PP \f(CW\*(C`GET\*(C'\fR .IX Subsection "GET" .PP Request goes to finalization with 404 status. .PP \f(CW\*(C`POST\*(C'\fR .IX Subsection "POST" .PP Request goes to \f(CW\*(C`allow_missing_post\*(C'\fR, which always returns false in Web::MREST's implementation. .PP After that, the request goes to finalization with 404 status. .PP If the .PP \f(CW\*(C`PUT\*(C'\fR .IX Subsection "PUT" .ie n .SS """finish_request""" .el .SS "\f(CWfinish_request\fP" .IX Subsection "finish_request" The previous sections should suffice for the reader to gain a degree of understanding of how the state machine works for various types of requests, and how Web::MREST interfaces with the response handlers. .PP The last cog of the \s-1FSM\s0 is \f(CW\*(C`finish_request\*(C'\fR. .SH "IN-DEPTH DISCUSSIONS OF VARIOUS TOPICS" .IX Header "IN-DEPTH DISCUSSIONS OF VARIOUS TOPICS" .SS "Resource definitions" .IX Subsection "Resource definitions" As we read in the \*(L"crash course\*(R" above, resources are central to what a \s-1REST\s0 server is and does: the server processes incoming requests. Each request has a \s-1URI\s0 which resolves (or does not resolve) to a resource. Resources are defined as module variables: each module that contains resource handlers should also define a module variable (via \f(CW\*(C`our $resource_defs = { ... };\*(C'\fR) containing the definitions of the resources covered by that module. .PP The top-level dispatch module, Web::MREST::Dispatch, should implement a method called \f(CW\*(C`init_router\*(C'\fR which calls the function .PP .Vb 1 \& Web::MREST::InitRouter::load_resource_defs .Ve .PP for all the resource-defining modules. When the first \s-1HTTP\s0 request comes in, Web::MREST::Resource calls the \f(CW\*(C`init_router\*(C'\fR method. This only happens once, ensuring that the resource definitions are fully loaded for the first \- and all subsequent \- requests. .PP Each resource definition is a hashref consisting of a number of properties. This definition hashref is itself included in the \f(CW$resources\fR package hashref, which essentially looks like this: .PP .Vb 5 \& { \& RESOURCE_NAME => RESOURCE_DEFINTION, \& RESOURCE_NAME => RESOURCE_DEFINTION, \& RESOURCE_NAME => RESOURCE_DEFINTION, \& } .Ve .PP where \f(CW\*(C`RESOURCE_NAME\*(C'\fR is a resource name (a string like \f(CW\*(Aq/\*(Aq\fR or \&\f(CW\*(Aqdocu/text\*(Aq\fR) and \f(CW\*(C`RESOURCE_DEFINITION\*(C'\fR is that resource's definition hashref. .PP The root resource should be defined under the name \f(CW\*(Aq/\*(Aq\fR and top-level resources should have a \f(CW\*(C`parent\*(C'\fR property set to this string. .PP In the resource definition, properties can be specified either as a scalar value, in which case the definition applies to all the methods specified in \f(CW\*(C`$site\->MREST_SUPPORTED_HTTP_METHODS\*(C'\fR, or as a hashref in case the given resource is only defined for certain methods. .PP In the latter case, it is not necessary to define all properties as hashrefs. The set of permitted methods will always be taken from the \&'handler' property. For example in this snippet whizzo_resource is only defined for the \s-1GET\s0 method, and that will be applied to 'foo' (and the rest of this resource's properties) as well. .PP .Vb 7 \& \*(Aqwhizzo_resource\*(Aq => { \& \*(Aqhandler\*(Aq => { \& \*(AqGET\*(Aq => \*(Aqsome_method\*(Aq, \& }, \& \*(Aqfoo\*(Aq => \*(Aqbarbazbat\*(Aq, \& ... \& } .Ve .PP So 'foo' will only be defined for the \s-1GET\s0 method. .PP Examples: .PP .Vb 1 \& \*(Aqfoo_prop\*(Aq => \*(Aqvalue applied to all available methods\*(Aq, \& \& \*(Aqbar_prop\*(Aq => { \& \*(AqGET\*(Aq => \*(Aqvalue applied to GET requests\*(Aq, \& \*(AqPOST\*(Aq => \*(Aqvalue applied to POST requests\*(Aq, \& }, .Ve .PP There is one required property, 'handler', which is used to specify the handler(s) for the resource (see the examples below). The value of this property is taken to be the name of a method. This method call looks like this: .PP .Vb 1 \& $self\->$handler .Ve .PP and is located in Web::MREST::Resource\->resource_exists .PP (The inheritance chain is set up in \f(CW\*(C`bin/mrest\*(C'\fR \- the server startup script \- and via \f(CW\*(C`use parent\*(C'\fR statements in the various modules that make up the inheritance chain.) .PP In addition, each resource may have any properties you, the application developer, wish to invest in it. For our 'docu' methods we use the properties 'description' and 'documentation', for example. .PP Two properties \- 'parent' and 'validations' \- are exceptions to the above and should never be defined on a per-method basis: .PP .Vb 3 \& \- \*(Aqvalidations\*(Aq contains validation checks to be applied when matching \& URI to resource (for more information, see the Path::Router \& documentation). \& \& \- \*(Aqparent\*(Aq contains the name of the resource\*(Aqs parent resource \& (defaults to \*(Aq\*(Aq \- the root resource) \& \& \- \*(Aqdocumentation\*(Aq is reserved for the self\-documentation feature .Ve .PP \fI\f(CI\*(C`Path::Router\*(C'\fI object initialization\fR .IX Subsection "Path::Router object initialization" .PP When the server starts, the \f(CW\*(C`MREST_RESOURCE_DEFINITIONS\*(C'\fR and \&\f(CW\*(C`MREST_ROOT_RESOURCE\*(C'\fR meta parameters are initialized from the configuration file \f(CW\*(C`config/dispatch_MetaConfig.pm\*(C'\fR in the Web::MREST distribution. .PP The application developer will of course want to define her own set of resources. This should be done by manipulating the meta parameters \&\f(CW\*(C`MREST_RESOURCE_DEFINITIONS\*(C'\fR and \f(CW\*(C`MREST_ROOT_RESOURCE\*(C'\fR. A good place to do this is in the application's \f(CW\*(C`mrest_init_router\*(C'\fR routine. .PP Here are two approaches to defining the application's resources, depending on whether the application wishes to retain the Web::MREST resources. .IP "1. retain" 4 .IX Item "1. retain" .Vb 1 \& package MyApp::Resource; \& \& use Clone \*(Aqclone\*(Aq; \& use parent \*(AqWeb::MREST::Resource\*(Aq; \& \& # We assume that the application somehow loads its resource definitions \& # (including the root resource) into a package variable $r_defs \-\- for \& # example by hard\-coding them like this \& my $r_defs = { ... }; \& \& # \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \& # mrest_init_router \- called by Web::MREST \& # \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \& sub mrest_init_router { \& my $self = shift; \& \& # set up the root resource \& $meta\->set( \*(AqMREST_ROOT_RESOURCE\*(Aq, $r_defs\->{\*(Aq\*(Aq} ); \& delete $r_defs\->{\*(Aq\*(Aq}; \& \& # set up the remaining resources, retaining (but possibly \& # overwriting) the Web::MREST default resources \& my $mrest_defs = clone( $meta\->MREST_RESOURCE_DEFINITIONS ); \& foreach my $r_name ( keys %$r_defs ) { \& $mrest_defs\->{$r_name} = $r_defs\->{$r_name}; \& } \& $meta\->set( \*(AqMREST_RESOURCE_DEFINITIONS\*(Aq, $mrest_defs ); \& } .Ve .IP "2. do not retain" 4 .IX Item "2. do not retain" This approach is more simple because no \f(CW\*(C`mrest_init_router\*(C'\fR need be written. The application should have its own distro sharedir \f(CW\*(C`config/\*(C'\fR and therein a file \f(CW\*(C`dispatch_MetaConfig.pm\*(C'\fR. Inside that file, the application puts its own resource definitions in the \f(CW\*(C`MREST_RESOURCE_DEFINITIONS\*(C'\fR and \&\f(CW\*(C`MREST_ROOT_RESOURCE\*(C'\fR parameters (refer to \f(CW\*(C`config/dispatch_MetaConfig.pm\*(C'\fR in the Web::MREST distribution for syntax and semantics). .Sp The application's definitions will overlay (i.e. replace) those of Web::MREST. Even in this scenario, some or all of Web::MREST's resources could be used in the application, but only by copy-pasting the definitions and their respective handlers into the application's source code. .PP \fITree structure\fR .IX Subsection "Tree structure" .PP Web::MFILE allows resources to be defined in a tree structure. It is designed to allow a tree structure to be described in a flat configuration file. The \f(CW\*(C`MREST_RESOURCE_DEFINITIONS\*(C'\fR hash is keyed on the resource name. Child resources are indicated by including a \f(CW\*(C`parent\*(C'\fR property with the name of the parent resource. Care should be exercised not to introduce any circular references. .PP If a flat structure is desired, simply do not include any \f(CW\*(C`parent\*(C'\fR properties in your resource definitions. .PP The format of \f(CW\*(C`MREST_RESOURCE_DEFINITIONS\*(C'\fR hash is documented in \&\f(CW\*(C`config/dispatch_MetaConfig.pm\*(C'\fR. .PP \fI\f(CI$Web::MREST::InitRouter::resources\fI\fR .IX Subsection "$Web::MREST::InitRouter::resources" .PP The resource definition hashrefs in the dispatch modules are designed to be written and maintained by humans. When the \f(CW\*(C`init_router\*(C'\fR method runs, it loops over all the resource definitions and builds up a second hash, \&\f(CW$Web::MREST::InitRouter::resources\fR, which contains the same information in a format that is more convenient for automated processing. .PP Since the resource definitions are a potential source of typographical and semantic errors, you should dump this package variable to the log and examine it to make sure your resource definitions are being processed correctly. .SS "Errors" .IX Subsection "Errors" As we move through the state machine (i.e. the chain of method calls driven by Web::Machine), we build up a \*(L"context\*(R" from which we generate the \s-1HTTP\s0 response. Stated very simply, the response code can either be '\s-1OK\s0' (200) or \&\*(L"something else\*(R" \- i.e., an error of some kind. .PP And, indeed, checking for errors accounts for a large portion of what our resource modules do. As \s-1RFC2616\s0 explains, errors can be divided into two brought classes: client errors and server errors. .IP "Client errors (4xx)" 4 .IX Item "Client errors (4xx)" Client errors have status codes that start with 4 (e.g. 400, 401, 404). .Sp \&\s-1RFC2616\s0 has this to say about them: .Sp .Vb 6 \& The 4xx class of status code is intended for cases in which the client \& seems to have erred. Except when responding to a HEAD request, the server \& SHOULD include an entity containing an explanation of the error situation, and \& whether it is a temporary or permanent condition. These status codes are \& applicable to any request method. User agents SHOULD display any included \& entity to the user. .Ve .IP "Server errors (5xx)" 4 .IX Item "Server errors (5xx)" Server errors have codes beginning with th digit \*(L"5\*(R". According to \s-1RFC2616,\s0 they .Sp .Vb 6 \& indicate cases in which the server is aware that it has erred or is \& incapable of performing the request. Except when responding to a HEAD \& request, the server SHOULD include an entity containing an explanation of \& the error situation, and whether it is a temporary or permanent condition. \& User agents SHOULD display any included entity to the user. These response \& codes are applicable to any request method. .Ve .PP The key point here is that it is not sufficient to return a bare 4xx or 5xx response status code. The response should include an entity body with an explanation of the error condition. .PP \fIHow to provide explanation in response entity\fR .IX Subsection "How to provide explanation in response entity" .PP Web::MREST provides a mechanism for adding the explanation to the entity body as called for by \s-1RFC2616.\s0 At the exact place in your resource module where you discover the error, do something like this: .PP .Vb 1 \& $self\->mrest_declare_status( code => \*(Aq400\*(Aq, explanation => \*(AqYou messed up\*(Aq ); .Ve .PP This will be converted into the respective App::CELL::Status object and returned in the response entity. The object will have properties like this: .PP .Vb 11 \& { \& level => \*(AqERR\*(Aq, \& code => \*(AqYou messed up\*(Aq, \& payload => { \& http_code => \*(Aq500\*(Aq, \& uri_path => ... (taken from the context), \& resource_name => ... (taken from the context), \& found_in => ... (taken from \*(Aqcaller\*(Aq), \& permanent => JSON::true (the default), \& }, \& } .Ve .PP Alternatively, you can pass in your own arbitary App::CELL::Status object. .PP To see how the App::CELL::Status object becomes the response entity, see the \f(CW\*(C`finish_request\*(C'\fR method in Web::MREST::Resource. .SS "Context" .IX Subsection "Context" Typically referred to as \f(CW$context\fR, the \*(L"\s-1MREST\s0 context\*(R" is a hashref that is built up during the course of request processing. In addition to being used within Web::MREST::Resource, it is always sent as an argument whenever Web::MREST::Resource calls a hook, so the developer can modify it in her implementations of the various hook routines. .SS "Authentication" .IX Subsection "Authentication" Ever since the Big Bad Wolf ate Granny, authentication mechanisms have been prone to abuse by individuals who are willing to lie about their identity. .PP Humans are good at distinguishing one human from another, provided they can apply all their senses to the task. Computers lack proper senses and are downright awful at this task. Computerized authentication schemes typically operate by presenting the user with one or more hoops to jump through. Whoever succeeds at this task is deemed to be the user. What could go wrong? .PP Passwords (or passphrases) are the \*(L"hoop\*(R" most frequently used to authenticate users and keep would-be intruders out. Therefore, a system's security is often gauged by how well it protects user credentials from disclosure. Since usernames are public, the only thing keeping a determined intruder at bay are the passwords, and various measures are taken to protect them. .PP From the perspective of Web::Machine, authentication is a matter of calling the is_authorized method. If the return value is false, the response will be \f(CW\*(C`401 Unauthorized\*(C'\fR. If it is true, request processing continues. Whatever authentication measures the application developer decides to implement should be triggered by this method call. .PP For more about is_authorized, see the Web::Machine::Resource documentation .SS "Authorization" .IX Subsection "Authorization" Once authentication has determined the user's identity, a related task, authorization, begins. As the name would imply (and the \s-1RFC\s0's vague use of the term \*(L"authorization\*(R" notwithstanding), authorization answers the question: .PP .Vb 1 \& Is this specific user authorized to make this request? .Ve .PP Compare this with authentication, which answers a different question: .PP .Vb 1 \& Is this user really who they are purporting to be? .Ve .PP Or, even more pithily: .PP .Vb 1 \& Who is this user? .Ve .PP Authorization implies a boolean \*(L"function\*(R" (in both the mathematical and computer science sense) that takes three arguments: the username, the \s-1HTTP\s0 method, and the resource. Implementation of this function is left to the application developer. .PP It is worth noting here that Web::Machine provides a \f(CW\*(C`forbidden\*(C'\fR method. Since \f(CW\*(C`is_authorized\*(C'\fR is already taken for authentication, we can use \&\f(CW\*(C`forbidden\*(C'\fR for authorization. Just be sure to understand thoroughly that a true return value from \f(CW\*(C`forbidden\*(C'\fR means \*(L"not authorized\*(R". .SS "Customized \s-1URI\s0 parsing" .IX Subsection "Customized URI parsing" While Web::MREST provides for \s-1URI\s0 parsing using Path::Router, if this is not desired the application developer can parse URIs herself by simply substituting her own \f(CW\*(C`init_router\*(C'\fR and \f(CW\*(C`match\*(C'\fR methods for the ones provided by Path::Router and Path::Router::Route::Match, respectively. .PP When request processing enters \f(CW\*(C`resource_exists\*(C'\fR, Alternatively, the application developer can overlay the \f(CW\*(C`init_router\*(C'\fR routine with one that returns an arbitrary object (stored in \f(CW$router\fR) that has a \&\f(CW\*(C`match\*(C'\fR method. After that, Web::MREST does .PP .Vb 1 \& my $match = $router\->match( $path ); .Ve .PP where \f(CW$path\fR is the relative portion of the \s-1URI\s0 (i.e. everything left after the \f(CW\*(C`http://myapp.example.com/\*(C'\fR part is cut off). .PP The \f(CW$match\fR object should provide a \f(CW\*(C`route\*(C'\fR method, which should return the definition of the matched resource. See \*(L"\s-1RESOURCE DEFINITIONS\*(R"\s0. .SH "FUNCTIONS IN THIS MODULE" .IX Header "FUNCTIONS IN THIS MODULE" .SS "init" .IX Subsection "init" Do initialization-like things, such as loading configuration parameters. Takes a \s-1PARAMHASH\s0 which can contain one of the following: .ie n .IP """distro""" 4 .el .IP "\f(CWdistro\fR" 4 .IX Item "distro" The name of the application distribution from which the distro sharedir will be loaded. .ie n .IP """path""" 4 .el .IP "\f(CWpath\fR" 4 .IX Item "path" The name (full path) of a directory containing the application's configuration files. .ie n .IP """hashref""" 4 .el .IP "\f(CWhashref\fR" 4 .IX Item "hashref" A reference to a hash containing meta parameters to be loaded. .SS "version" .IX Subsection "version" Accessor method (to be called like a constructor) providing access to \f(CW$VERSION\fR variable