NAME
App::MFILE::WWW - generic web front-end with demo app
VERSION
Version 0.079
LICENSE
This software is distributed under the "BSD 3-Clause" license, the text of which can be found in the file named COPYING
in the top-level distro directory. The license text is also reprodued at the top of each source file.
DESCRIPTION
This distro contains a generic framework for developing web front-ends to REST resources. The framework includes a web server (based on Plack and Web::Machine), CSS and HTML for the "frame" where the application displays its screens, and "widgets" for defining the application's login dialog, menus, forms, and actions.
For illustration, the distro contains a demo app that works with App::Dochazka::REST.
INTRODUCTION
The full stack, of which App::MFILE::WWW is a part, consists of the following components:
Database engine
For storing application data.
Perl DBI
For interfacing between the Perl code and the database engine.
REST server
A REST server, such as App::Dochazka::REST, implements a data model and provides a HTTP interface to that model.
optional CLI client/frontend
An optional Command Line Interface (frontend) can provide a command line interface to the REST server.
WWW client/frontend
The WWW frontend, based on this distro, is a web server that serves HTML, CSS, and JavaScript code to users for a menu-driven "browser experience" of the application.
Conceptually, the clients act as proxies between the user and the REST server. Taking this one step further, the REST server itself is a proxy between the client and the database engine.
The philosophy behind this design is that you, the user, have the freedom and the flexibility to write your own client, on any platform, in any language -- however you see fit.
MAJOR COMPONENTS
The web frontend is implemented using the following technologies:
Perl - server-side code
nginx - reverse proxy (optional)
HTTP::Server::PSGI, Starman, or other PSGI-compatible HTTP server
Plack - interface with HTTP server
Web::Machine - HTTP request/response cycle
App::MFILE::WWW::Resource - overlays Web::Machine::Resource
HTML and CSS code served to the user's browser
JavaScript code served to and running in the user's browser
AJAX calls from the JavaScript code back to the web server, which forwards them to the REST server and sends the results back to the JavaScript side - see the next section for details
Request-response cycle
A more detailed description of the request-response cycle implemented by App::MFILE::WWW:
nginx listens for incoming connections on port 80/443 of the server
When a connection comes in, nginx decrypts it and forwards it to a high-numbered port where Starman is listening
Starman takes the connection and passes it to the Plack middleware
the key middleware component is Plack::Middleware::Session, which assigns an ID to the session, maintains whatever data the server-side code needs to associate with the session, links the session to the user's browser via a cookie, and provides the application a hook (in the Plack environment that is included in the HTTP request) to access the session data
if the connection is asking for static content (defined as anything in
images/
,css/
, orjs/
), Plack and Starman serve that content immediately and the request doesn't even make it into our codeany other path is considered dynamic content and is passed to Web::Machine for processing -- Web::Machine implements the HTTP standard as a state machine
the Web::Machine state machine takes the incoming request and runs it through several functions that are implemented in App::MFILE::WWW::Resource -- for example, 'malformed_request' examines the request body, if any, and if it is not valid JSON, the HTTP server returns '400 Malformed Request'
as part of the state machine, all incoming requests are subject to "authorization" (in the HTTP sense), which actually means authentication. First, the session data is examined to determine if the request belongs to an authorized session. If it doesn't, the request is treated as a login/logout attempt.
once an authorized session is established, there are two types of requests: GET and POST
incoming GET requests can happen when the page is reloaded - in an authorized session, this causes the main menu to be displayed. JavaScript form buffers and other data structures are reset to their default values. Note that App::MFILE::WWW pays no attention to the URI - if the user enters a path (e.g. http://mfile.site/some/bogus/path), this will be treated like any other page reload.
if the session is expired or invalid, any incoming GET request will cause the login dialog to be displayed.
well-formed POST requests are assumed to be AJAX calls and are processed by the
process_post
routine. First, the request body is examined. The request body of all AJAX calls must adhere to a simple structure:{ method: "GET", path: "employee/current", body: { ... } }
where 'method' is either GET or POST, 'path' is the path to the REST server resource being requested, and 'body' is the request body to be forwarded to the REST server. Provided the request is properly authorized and the body is well-formed, the request is forwarded to the REST server and the REST server's response is sent back to the user's browser, where it is processed by the JavaScript code.
under ordinary operation, the user will spend 99% of her time interacting with the JavaScript code running in her browser, which will communicate asynchronously with the REST server via AJAX calls as described above.
Development notes
UTF-8
In conformance with the JSON standard, all data passing to and from the server are assumed to be encoded in UTF-8. Users who need to use non-ASCII characters should check their browser's settings.
Deployment
To minimize latency, App::MFILE::WWW can be deployed on the same server as the back-end (e.g. App::Dochazka::REST), but this is not required.
PACKAGE VARIABLES
For convenience, the following variables are declared with package scope:
FUNCTIONS
init
Initialization routine - runs when the server is started. Loads configuration files from the distro and site configuration directories, and sets up logging.