The holism package implements an HTTP 1.1 web application server and REST framework for Node.js that is designed to enable rapid prototyping and integration of plug-in features that are easily composed and reusable across projects.
Holism works by routing HTTP requests through a declaratively configured processing pipeline that connects the Node.js http.ClientRequest and http.ServerResponse stream classes.
+-------------------+
http.ClientRequest -> | Holism App Server | -> http.ServerResponse
+-------------------+
Internally holism's request processing pipeline is defined as a series of intrinsic and developer-defined operations that are specialized to handle application-specific data types using declarative filter specifications and ARCcore.filter objects responsible for API contract enforcement and error handling.
A simplied version of the holism request pipeline shown below.
+------------------+ #================# +-------------+
http.ClientRequest -> | Deserialization | -> | User Authorize | -> | Routing | ---> (1)
+------------------+ #================# +-------------+
####################
(1) ---> | Static Resources | ---> (4) +-------------+
#################### | intrinsic |
+-------------+
####################
(1) ---> | Plug-in Services | ---> (3)(4) #=============#
#################### | integration |
#=============#
+------------------+
(*) ---> | Error Processing | ---> (3) ###############
+------------------+ | route |
###############
#==================#
(3) ---> | HTML Rendering | ---> (4)
#==================#
+------------------+
(4) ---> | Serialization | -> http.ServerResponse
+------------------+
The entire request processing pipeline is built from and extended with ARCcore.filter objects that rigorously scrutinize data passing through the pipeline providing:
Additionally, because holism application server instances are composed of decoupled plug-in components that are registered and configured declaratively its easy to automate the creation of derived applications and services from data. For example, a custom script could query a database and synthesize a customized application for interacting with the data.
See Holism Server Factory for complete discussion.
An instance of a Holism app server is created by calling a software factory that requires three
inputs that are explained in more detail below. If you provide these three inputs in the correct
format and no error occurs in the factory, then the factory returns an object with method listen
.
+----------------+
app integration filters ---------> | | +-------------------+
static resources registrations --> | Holism Factory | --> | Holism App Server |
service filter registrations ----> | | +-------------------+
+----------------+
Ignoring the details of the three factory input parameters for the moment, creating a new Holism app server instance is simple and prescriptive:
const holism = require('holism');
// Call the Holism app server factory to create a new instance.
var factoryResponse = holism.server.create({
name: "Test Server",
description: "Simple example server.",
version: "0.0.1",
config: {
files: { /* dictionary of static resource registrations */ },
services: [ /* array of HTTP service filter registrations */ ]
},
integrations: { /* app integration filters descriptor object */ }
});
// Ensure that no error occurred in the factory.
if (factoryResponse.error) {
throw new Error(factoryResponse.error); // GAME OVER. Thank you for playing.
}
// De-reference the Holism app server instance.
var holismServer = filterResponse.result;
Once you have constructed Holism app server instance, start the service by calling the listen
method
specifying the TCP/IP port you want to receive incoming HTTP requests on:
holismServer.listen(4771);
Assuming you're running on localhost, pointing your browser at http://localhost:4771
should
now load the homepage of your application.
At present, Holism only supports HTTP. This decision was made to limit the scope of the v1 project and because typically Holism instance(s) are deployed on a private subnet behind a proxy/load balancer when used in a production environment.
For example, this app is served by a Holism instance that communicates via HTTP over an OpenVPN-secured private subnet to an HAProxy instance that handles both load balancing and HTTPS encryption functions. Another popular options is NGINX.
See Holism Static Resources for complete discussion.
Static resources are assets (e.g. files) that do not change during the lifespan of a Holism server instance. These resources are loaded at server instance startup and mapped to one or more unique URL's bound to HTTP method GET. For example, image resources such as the SVG-format icons used on this site are declared to the Holism server factory as static resources. As well, the JavaScript bundle produced with webpack that powers the client-side of this website is served as a static resource.
Static resources are cached in memory when the server instance starts along with each resource's unique digest
hash signature. When a new HTTP GET request for a specific resource is received by the Holism instance
the server looks to see if the request contains the If-None-Match
HTTP header with a current digest hash
value for the resource. If it does, the server responds with HTTP response code 304 indicating that the client
should use the copy of the resource stored in its local cache. If the HTTP request does not contain the
If-None-Match
header, or if the digest hash signature specified does not match the server instance's signature
the server instance transfers the resource from its memory cache and attaches an ETag
HTTP header to the
response containing the current digest hash signature.
This feature is very simple for developers to use but trades off memory for speed and convenience. If you need to serve a large number of big resources, you're better off serving them via a service that pulls the bits on demand from an external store (e.g. a database or purpose-built memory cache such as RedisLabs Redis noSQL store).
To see the caching behavior in action, open your debugger and audit network traffic. Then click
Bronze Wall (JPG) to load an image of architect Frank Gehry's Experience Music
Project building here in Seattle. Note the difference in HTTP response code (200 vs 304) and values of
If-None-Match
and ETag
HTTP headers between the first and subsequent requests for the same resource.
See Holism Integration Filters Factory for complete discussion.
+-------------+
org metadata filter specification --------> | Holism |
org metadata get function (sync) ---------> | Application |
site metadata filter specification -------> | Integration |
site metadata get function (sync) --------> | Filters |
page metadata filter specification -------> | Factory | #=========================#
page metadata get function (sync) --------> | | --> | app integration filters |
user identity data filter specification --> | | #=========================#
user identity access function (sync) -----> | |
user session data filter specification ---> | |
user session access function (async) -----> | |
HTML document render function (sync) -----> | |
app state context (opaque reference) -----> | |
+-------------+
See Holism Service Filter Factory for complete discussion.
+---------+
name ----------------------------------------> | Holism |
description ---------------------------------> | HTTP |
id ------------------------------------------> | Service |
HTTP request content encoding ---------------> | Filter |
HTTP request content type -------------------> | Factory |
HTTP request query filter specification -----> | | ######################
HTTP request data filter specification ------> | | --> |HTTP service filter |
HTTP service filter options specification ---> | | ######################
HTTP request handler function (async) -------> | |
HTTP response content encoding --------------> | |
HTTP response content type ------------------> | |
HTTP response result filter specification ---> | |
HTTP response error filter specification ----> | |
+---------+