Pintura is a REST-style web framework that provides a comprehensive solution for Ajax-based thin-server applications. However, Pintura has a very modular design, and many of the modules in Pintura are extremely useful as standalone JavaScript/CommonJS components that can be used with Node, Narwhal and other projects. Let’s look at the JSGI middleware modules. JSGI middleware modules are designed to be used in a JSGI HTTP request handling stack, adding functionality to a web application. An example of using a JSGI middleware:
exports.app = MiddleWare( // wrapped my application with middleware
function(request){
... my JSGI application ...
});
All of Pintura’s middleware modules are JSGI 0.3 compliant and fully support promise-based asynchronous request/response handling.
- jsgi/csrf – The
csrf
middleware module will detect if a request may have been generated by a web page from a different server origin. If it is possible that the request came from a different origin, thecrossSiteForgeable
property of the request is set to true. Generally, such requests should be treated with suspicion. The request may still include cookies that were used for authentication and authorization, but any authorization module should be aware that the requesting agent may not be authorized to actually utilize these cookies for authorization. - jsgi/xsite – While the
csrf
module protects against unauthorized cross-site requests, thexsite
helps enable authorized cross-site requests. Thexsite
module actually consists of three middleware components:- JsonP – This adds support for JSONP requests. This will wrap requests with the proper callback in order for the client to receive the response.
- WindowName – This adds support for window.name requests. This will wrap requests with the proper HTML in order for the client to read the response from an iframe’s name property.
- CrossSiteXhr – This adds support for native cross-site XMLHttpRequest (now available in modern browsers). This will add the appropriate HTTP headers to allow clients to read the responses.
- CrossSite – This combines all three of the above middleware to maximize the ability for authorized client’s to interact with the server from other page origins.
- jsgi/http-params – This allows for HTTP headers to be emulated through query parameters. This is useful for cross-site requests and hyperlinks where HTTP headers can not be directly specified, but applications expect to read HTTP headers.
- jsgi/conditional – This module implements handling HTTP conditional requests, checking
If-Match
andIf-None-Match
againstETag
headers, and checkingIf-Modified-Since
andIf-Unmodified-Since
againstLast-Modified
headers, modifying and returning the appropriate HTTP responses when conditions indicate a 304 Not Modified (which improves performance) and 412 Precondition Failed (to avoid conflicting changes). - errors + jsgi/error – jsgi/error is a JSGI middleware module that catches errors and converts them into appropriate HTTP response codes. There are a variety of error constructors defined in the
errors
module (which is actually in the Perstore project) that correspond to the different HTTP status codes. For example:var MethodNotAllowedError = require("errors").MethodNotAllowedError, ErrorHandler = require("./jsgi/error").ErrorHandler; exports.app = ErrorHandler(function(request){ // my JSGI app, switch(request.method){ case "GET": ... default: throw new MethodNotAllowedError(); } });
This would allow you to throw an error, break out of the current stack, be caught by the ErrorHandler, and be converted to a 405 response code.
- jsgi/media – This module acts as “cross-over” middleware and performs HTTP content negotiation to choose the best content type (AKA media type). This makes it easy to have a RESTful selection of different representations for each data resource. This middleware wraps an application stack that is allowed to return JavaScript objects, arrays, and any other data values for a response body. Then, this middleware serializes the data to the best possible media type raw format. The media middleware module and the media type handlers also include support for deserializing raw binary/text data from requests into JavaScript data.
Pintura has a collection of different media type handlers that for serializing and deserializing data to and from different formats. Some of the important media handlers include:- json – JSON media handler
- javascript – Similar to the JSON media handler, but will serialize to additional JavaScript specific types such as dates, NaN, functions, and other types that do not exist in JSON.
- multipart-form-data and url-encoded – Used for parsing form data.
Pintura includes several more middleware modules that are designed to work downstream of the media module, expecting deserialized input and expecting JavaScript objects and arrays for the body (rather than normal JSGI body values). These are designed to interact with the object store API used by Perstore. These are generally more Pintura specific, but may still be used with proper integration:
- jsgi/faceted – This finds the appropriate facets for the authenticated user for accessing the models/stores
- jsgi/metadata – This sets and retrieves metadata from objects, translating from headers.
- jsgi/auth – This performs authentication against a provided object store, and saves authentication tokens in a cookie for maintaining authentication.
- jsgi/rest-store – This is the core Pintura application for delegating requests to the store facets and models.
- jsgi/transactional (this one lives in Perstore) – This wraps each request in a transaction.
With these modular middleware components, one can easily cherry-pick from Pintura in building custom stacks, or rearrange the middleware stack in Pintura applications. The Pintura framework itself is essentially a middleware stack. The Pintura middleware set is designed for REST-style standards-compliant web applications, and can be useful for any server -side JavaScript REST application regardless of whether or not you are using the entire Pintura framework.