NAME
MPMinus::REST - Base class of the MPMinus REST server
VERSION
Version 1.00
SYNOPSIS
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!!
});
DESCRIPTION
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.
REST AND CRUD
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
PRINCIPIES OF REST
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.
HTTP METHODS
Use HTTP methods to map CRUD (create, retrieve, update, delete) operations to HTTP requests.
GET
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
POST
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
PUT
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.
PATCH
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
DELETE
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
HTTP 1.1 STATUS CODES
- 1XX - informational
-
100 HTTP_CONTINUE Continue 101 HTTP_SWITCHING_PROTOCOLS Switching Protocols
- 2XX - success
-
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
- 3XX - redirection
-
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
- 4XX - client error
-
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
- 5XX - server error
-
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
MEDIA TYPES
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.
CONFIGURATION
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
METHODS
handler
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");
}
init
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
- location, base
-
It is part of the URL-path that will bases for your REST methods, e.g., "/", "rest", "/foo"
- prefix
-
Prefix name for signing LOG-strings and your files. Default: name of your server class
- blank
-
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
- dvars, valid_dvars
-
Defines defaults for variables specified in the httpd.conf <Location>, <Directory>, and <Files> section
Defaults:
{ debug => 'off', location => 'default', },
- sr_attrs
-
Defines dafaults for CTK::Serializer
Defaults:
{ 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, }, ], }
registered_servers
my @servers = $self->registered_servers();
Returns list of the defined RAMST server's instances
error_response
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
HANDLER METHODS
You can override all of these methods in your class
hInit
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
hAccess
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
Type: RUN_ALL
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hAuthen
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
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hAuthz
The Authz handler method
sub hAuthz {
my $self = shift;
my $r = shift;
# ... your statements ...
return $self->SUPER::hAuthz($r);
}
By default the method nothing to do and returns Apache2::Const::DECLINED response code
Type: RUN_FIRST
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hType
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
Type: RUN_FIRST
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hFixup
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
Type: RUN_ALL
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hResponse
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
Type: RUN_FIRST
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hLog
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
Type: RUN_ALL
See http://perl.apache.org/docs/2.0/user/handlers/http.html
hCleanup
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
Type: RUN_ALL
See http://perl.apache.org/docs/2.0/user/handlers/http.html
VARIABLES
MPMinus REST supports current session variables (svars), directory-variables (dvars) and data variables (data)
SESSION VARIABLES
Session variables are set only per session and are valid only within the current request
- debug
-
Defines DEBUG flag. Contains boolean values 0 or 1
Default: 0
Defined in: hInit
- format
-
Format name of the current transaction
Possible values: xml, yaml, json, none
Default: none
Defined in: hType
- hitime
-
High time value (microseconds)
Defined in: hInit
- key
-
Key of the current handler
Default: GET#/#default
Defined in: hInit
- method
-
Current HTTP method
Default: GET
Defined in: hInit
- name
-
Name of the current handler
Default: ""
Defined in: hResponse
- path
-
Current URL-path
Default: /
Defined in: hInit
- query
-
Current URL-query string
Default: ""
Defined in: hInit
- remote_addr
-
Current remote client IP address
Default: 127.0.0.1
Defined in: hAccess
- serializer
-
Serializer object
Default: undef
Defined in: hFixup
- sid
-
Session ID
Defined in: hInit
- deserialize_attr
-
Deserialize attributes
Default: undef
Defined in: hFixup
- serialize_attr
-
Serialize attributes
Default: undef
Defined in: hFixup
DIRECTORY VARIABLES
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
-
Debug value
Possible values: on, yes, 1, off, no, 0
Default: off
- location
-
Base location name or path
Default: default
DATA VARIABLES
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:
{
q => undef, # CGI object
usr => {}, # User params (from QueryString or form-data)
req_data => '', # Request data
res_data => '', # Response data
}
- req_data
-
Request data
Sets in: hInit, hFixup
- res_data
-
Response data
Sets in: hResponse (RAMST handler)
- usr
-
User params (from QueryString or form-data)
Sets in: hInit
- q
-
CGI object
Sets in: hInit
HISTORY
See CHANGES
file
DEPENDENCIES
mod_perl2
, MPMinus, MPMinus::RAMST, CTK::Serializer, CGI
TO DO
See TODO
file
BUGS
* none noted
SEE ALSO
mod_perl2
, https://www.restapitutorial.com, https://spring.io/understanding/REST, https://restfulapi.net
AUTHOR
Serż Minus (Sergey Lepenkov) http://www.serzik.com <abalama@cpan.org>
COPYRIGHT
Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved
LICENSE
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/