MPMinus::REST - Base class of the MPMinus REST server
Version 1.00
PerlModule MyApp::REST PerlOptions +GlobalRequest +ParseHeaders <Location /> PerlInitHandler MyApp::REST </Location> <Location /foo> PerlInitHandler MyApp::REST PerlSetVar Location foo PerlSetVar Debug on </Location> package MyApp::REST; use base qw/MPMinus::REST/; sub handler : method { my $class = (@_ >= 2) ? shift : __PACKAGE__; my $r = shift; # ... preinit statements ... return $class->init($r); } sub hInit { my $self = shift; my $r = shift; # Dir config variables $self->set_dvar(testvalue => $r->dir_config("testvalue") // ""); # Session variables $self->set_svar(init_label => __PACKAGE__); return $self->SUPER::hInit($r); } __PACKAGE__->register_handler( # GET / handler => "getIndex", method => "GET", path => "/", query => undef, attrs => { foo => 'blah-blah-blah', #debug => 'on', # off #content_type => 'text/plain; charset=utf-8', #deserialize => 1, #deserialize_att => {}, serialize => 1, #serialize_att => {}, }, description => "Index", code => sub { my $self = shift; my $name = shift; my $r = shift; my $q = $self->get("q"); my $usr = $self->get("usr"); my $req_data = $self->get("req_data"); # Output my $uri = $r->uri || ""; $uri =~ s/\/+$//; $self->set( res_data => { foo_attr => $self->get_attr("foo"), name => $name, init_label => $self->get_svar("init_label"), server_status => $self->status, code => $self->code, error => $self->error, key => $self->get_svar("key"), path => $self->get_svar("path"), remote_addr => $self->get_svar("remote_addr"), location => $self->{location}, #data => $self->data, stamp => $self->{stamp}, dvars => $self->{dvars}, uri => $uri, usr => $usr, req_data => $req_data, servers => [$self->registered_servers], }); return 1; # Or 0 only!! });
This module allows you to quickly and easily write a mod_perl2 REST server
Please note! This module REQUIRES Apache 2.2+ and mod_perl 2.0+
So. And now about REST and RESTfull
Information bellow has been copied from page https://spring.io/understanding/REST
REST (Representational State Transfer) was introduced and defined in 2000 by Roy Fielding in his doctoral dissertation. REST is an architectural style for designing distributed systems. It is not a standard but a set of constraints, such as being stateless, having a client/server relationship, and a uniform interface. REST is not strictly related to HTTP, but it is most commonly associated with it.
The MPMinus::REST tries to keep its HTTP methods joined up with CRUD methods.
The acronym CRUD refers to all of the major functions that are implemented in relational database applications. Each letter in the acronym can map to a standard Structured Query Language (SQL) statement, Hypertext Transfer Protocol (HTTP) method (this is typically used to build RESTful APIs) or Data Distribution Service (DDS) operation:
CRUD | SQL | HTTP | RESTful| DDS | Prefix ------------------+--------+----------------+--------+-----------+-------- Create | INSERT | PUT/POST | POST | write | add Read (Retrieve) | SELECT | GET | GET | read/take | get/is Update (Modify) | UPDATE | PUT/POST/PATCH | PUT | write | set Delete (Destroy) | DELETE | DELETE | DELETE | dispose | del/rm
Note! Create - PUT with a new URI; POST to a base URI returning a newly created URI
Note! Update - PUT with an existing URI
Note! HTTP PATCH - When PUTting a complete resource representation is cumbersome and utilizes more bandwidth, e.g.: when you have to update partially a column
Resources expose easily understood directory structure URIs.
Representations transfer JSON or XML to represent data objects and attributes.
Messages use HTTP methods explicitly (for example, GET, POST, PUT, and DELETE).
Stateless interactions store no client context on the server between requests. State dependencies limit and restrict scalability. The client holds session state.
Use HTTP methods to map CRUD (create, retrieve, update, delete) operations to HTTP requests.
Retrieve information. GET requests must be safe and idempotent, meaning regardless of how many times it repeats with the same parameters, the results are the same. They can have side effects, but the user doesn't expect them, so they cannot be critical to the operation of the system. Requests can also be partial or conditional.
Retrieve an address with an ID of 1:
GET /addresses/1
Request that the resource at the URI do something with the provided entity. Often POST is used to create a new entity, but it can also be used to update an entity.
Create a new address:
POST /addresses
Store an entity at a URI. PUT can create a new entity or update an existing one. A PUT request is idempotent. Idempotency is the main difference between the expectations of PUT versus a POST request.
Modify the address with an ID of 1:
PUT /addresses/1
Note: PUT replaces an existing entity. If only a subset of data elements are provided, the rest will be replaced with empty or null.
Update only the specified fields of an entity at a URI. A PATCH request is neither safe nor idempotent (RFC 5789). That's because a PATCH operation cannot ensure the entire resource has been updated.
PATCH /addresses/1
Request that a resource be removed; however, the resource does not have to be removed immediately. It could be an asynchronous or long-running request.
Delete an address with an ID of 1:
DELETE /addresses/1
100 HTTP_CONTINUE Continue 101 HTTP_SWITCHING_PROTOCOLS Switching Protocols
200 HTTP_OK OK 201 HTTP_CREATED Created 202 HTTP_ACCEPTED Accepted 203 HTTP_NON_AUTHORITATIVE Non-Authoritative Information 204 HTTP_NO_CONTENT No Content 205 HTTP_RESET_CONTENT Reset Content 206 HTTP_PARTIAL_CONTENT Partial Content
300 HTTP_MULTIPLE_CHOICES Multiple Choices 301 HTTP_MOVED_PERMANENTLY Moved Permanently 302 HTTP_MOVED_TEMPORARILY Found 303 HTTP_SEE_OTHER See Other 304 HTTP_NOT_MODIFIED Not Modified 305 HTTP_USE_PROXY Use Proxy 306 (Unused) 307 HTTP_TEMPORARY_REDIRECT Temporary Redirect
400 HTTP_BAD_REQUEST Bad Request 401 HTTP_UNAUTHORIZED Unauthorized 402 HTTP_PAYMENT_REQUIRED Payment Required 403 HTTP_FORBIDDEN Forbidden 404 HTTP_NOT_FOUND Not Found 405 HTTP_METHOD_NOT_ALLOWED Method Not Allowed 406 HTTP_NOT_ACCEPTABLE Not Acceptable 407 HTTP_PROXY_AUTHENTICATION_REQUIRED Proxy Authentication Required 408 HTTP_REQUEST_TIMEOUT Request Timeout 409 HTTP_CONFLICT Conflict 410 HTTP_GONE Gone 411 HTTP_LENGTH REQUIRED Length Required 412 HTTP_PRECONDITION_FAILED Precondition Failed 413 HTTP_REQUEST_ENTITY_TOO_LARGE Request Entity Too Large 414 HTTP_REQUEST_URI_TOO_LARGE Request-URI Too Long 415 HTTP_UNSUPPORTED_MEDIA_TYPE Unsupported Media Type 416 HTTP_RANGE_NOT_SATISFIABLE Requested Range Not Satisfiable 417 HTTP_EXPECTATION_FAILED Expectation Failed
500 HTTP_INTERNAL_SERVER_ERROR Internal Server Error 501 HTTP_NOT IMPLEMENTED Not Implemented 502 HTTP_BAD_GATEWAY Bad Gateway 503 HTTP_SERVICE_UNAVAILABLE Service Unavailable 504 HTTP_GATEWAY_TIME_OUT Gateway Timeout 505 HTTP_VERSION_NOT_SUPPORTED HTTP Version Not Supported
See Apache Constants
The Accept and Content-Type HTTP headers can be used to describe the content being sent or requested within an HTTP request. The client may set Accept to application/json if it is requesting a response in JSON. Conversely, when sending data, setting the Content-Type to application/xml tells the client that the data being sent in the request is XML.
Accept
Content-Type
application/json
application/xml
The simplest configuration of MPMinus REST server requires a few lines in your httpd.conf:
PerlModule MyApp::REST PerlOptions +GlobalRequest +ParseHeaders <Location /> PerlInitHandler MyApp::REST </Location>
The <Location> section routes all requests to the MPMinus REST handler, which is a simple way to try out MPMinus REST
The main Apache mod_perl2 entry point. This method MUST BE overwritten in your class!
sub handler : method { my $class = (@_ >= 2) ? shift : __PACKAGE__; my $r = shift; # ... preinit statements ... return $class->init($r, arg1 => "foo", arg2 => "bar"); }
In your class of the server, you MUST SPECIFY the initializer call string that returns the mod_perl2 (Apache2::Const) code - common or http.
my $rc = $class->init($r, ...ARGUMENTS...);
As first parameter ($r) is the Apache2::RequestRec object
Arguments is a hash-pairs (list of name and values) of additional parameters for RAMST base class
It is part of the URL-path that will bases for your REST methods, e.g., "/", "rest", "/foo"
Prefix name for signing LOG-strings and your files. Default: name of your server class
Specifies blank-structure for RAMST working data in current request context. In the next request, all data will be reset according to the default data defined in the blank-structure.
Default blank is:
{ q => undef, # CGI object usr => {}, # User params (from QueryString or form-data) req_data => '', # Request data res_data => '', # Response data }
For get and set data please use get and set methods
Defines defaults for variables specified in the httpd.conf <Location>, <Directory>, and <Files> section
Defaults:
{ debug => 'off', location => 'default', },
Defines dafaults for CTK::Serializer
{ xml => [ { # Serialize RootName => "response", NoAttr => 1, }, { # Deserialize ForceArray => 1, ForceContent => 1, } ], json => [ { # Sserialize utf8 => 0, pretty => 1, allow_nonref => 1, allow_blessed => 1, }, { # Deserialize utf8 => 0, pretty => 1, allow_nonref => 1, allow_blessed => 1, }, ], }
my @servers = $self->registered_servers();
Returns list of the defined RAMST server's instances
sub error_response { my $self = shift; return { error => { code => $self->code, message => $self->error } } }
Defines error response format
You can override this method in your class
You can override all of these methods in your class
The First (Init) handler method
sub hInit { my $self = shift; my $r = shift; # Dir config variables $self->set_dvar(testvalue => $r->dir_config("testvalue") // ""); # Session variables $self->set_svar(init_label => __PACKAGE__); return $self->SUPER::hInit($r); }
By default the method performs:
Sets the hitime and the sid session variables (svars)
Checks the HTTP Method of the current request
Inits CGI query object and sets it as the "q" node in RAMST data structure
Inits usr structure from $q->param's (QUERY_STRING parsed params) and sets it as the "usr" node in RAMST data structure
Inits request data from REQUEST in "as-is" format and sets it as the "req_data" node in RAMST data structure
Sets "debug" session variable from dvars or RAMST handler's attributes
Type: RUN_ALL
See http://perl.apache.org/docs/2.0/user/handlers/http.html
The Access handler method
sub hAccess { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hAccess($r); }
By default the method sets remote_addr session variable from X-Real-IP header or remote_ip of Apache2::Connection method
The Authen handler method
sub hAuthen { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hAuthen($r); }
By default the method nothing to do and returns Apache2::Const::DECLINED response code
Type: RUN_FIRST
The Authz handler method
sub hAuthz { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hAuthz($r); }
The Type handler method
sub hType { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hType($r); }
By default the method sets the "format" session variable and sets Content-Type header according defined format
The Fixup handler method
sub hFixup { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hFixup($r); }
By default the method sets the "serializer" session variable and sets serializer's attributes as "deserialize_attr" and "serialize_attr" session variables (svars). Also this method sets the "req_data" data node according selected serialization
The Response handler method
sub hResponse { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hResponse($r); }
By default the method runs RAMST registered handler, gets data and prepare response content (or error response content), serialize it and sents to client
The Log handler method
sub hLog { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hLog($r); }
By default the method writes to system log status of the current request-transaction
The Cleanup handler method
sub hCleanup { my $self = shift; my $r = shift; # ... your statements ... return $self->SUPER::hCleanup($r); }
By default the method flushes the RAMST data node to blank-data structure, flushes session variables (svars) and resets status and errors of current RAMST server object
MPMinus REST supports current session variables (svars), directory-variables (dvars) and data variables (data)
Session variables are set only per session and are valid only within the current request
Defines DEBUG flag. Contains boolean values 0 or 1
Default: 0
Defined in: hInit
Format name of the current transaction
Possible values: xml, yaml, json, none
Default: none
Defined in: hType
High time value (microseconds)
Key of the current handler
Default: GET#/#default
Current HTTP method
Default: GET
Name of the current handler
Default: ""
Defined in: hResponse
Current URL-path
Default: /
Current URL-query string
Current remote client IP address
Default: 127.0.0.1
Defined in: hAccess
Serializer object
Default: undef
Defined in: hFixup
Session ID
Deserialize attributes
Serialize attributes
Variables obtained from the Apache configuration sections <Location>, <Directory> or <Files> using PerlSetVar and PerlAddVar directives.
These variables do not flushes automatically in cleanup handler, so the dvars pool can be used for persistent objects, e.g., DBI
Debug value
Possible values: on, yes, 1, off, no, 0
Default: off
Base location name or path
Default: default
These variables are initialized to BLANK structure and then modified from the handler to the handler. The Data variables are automatically flushes at the Cleanup handler.
By default BLANK is follow structure:
Request data
Sets in: hInit, hFixup
Response data
Sets in: hResponse (RAMST handler)
User params (from QueryString or form-data)
Sets in: hInit
CGI object
See CHANGES file
CHANGES
mod_perl2, MPMinus, MPMinus::RAMST, CTK::Serializer, CGI
mod_perl2
See TODO file
TODO
* none noted
mod_perl2, https://www.restapitutorial.com, https://spring.io/understanding/REST, https://restfulapi.net
Serż Minus (Sergey Lepenkov) http://www.serzik.com <abalama@cpan.org>
Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See LICENSE file and https://dev.perl.org/licenses/
LICENSE
To install MPMinus, copy and paste the appropriate command in to your terminal.
cpanm
cpanm MPMinus
CPAN shell
perl -MCPAN -e shell install MPMinus
For more information on module installation, please visit the detailed CPAN module installation guide.