Hosted by Three Crickets

Prudence
Scalable REST Platform
For the JVM

Prudence logo: bullfinch in flight

The URI-space

The "URI-space" represents the published set of all URIs supported by your server. "Supported" here means that unsupported URIs should return a 404 ("not found") HTTP status code. In other words, they are not in the URI-space.
Importantly, the URI-space can be potentially infinite, in that you may support URI templates that match any number of actual URIs (within the limitations of maximum URI length). For example, "/service/{id}/" could match "/service/1/", "/service/23664/", etc., and "/film/*" can match "/film/documentary/mongolia/", "/film/cinema/", etc. All URIs that match these templates belong to your URI-space.
Note that this definition also encompasses the HTTP "PUT" verb, which can be used to create resources (as well as override them). If your server allows for "PUT" at a specific set of URIs, then they are likewise part of your URI-space. In other words, you "support" them.
The URI-space is mostly configured in the application's routing.js file. However, your resource implementations can add their own special limits. For example, for the "/service/{id}/" URI template we can make sure in code that "{id}" would always be a decimal integer (returning 404 otherwise), thus effectively limiting the extent of the URI-space. More generally, Prudence supports "wildcard" URI templates, allowing you to delegate the parsing of the URI remainder entirely to your resource code. This chapter will cover it all.
Make sure to also read the URI-space Architecture article, which discusses general architectural issues.

routing.js

Routing is configured in your application's routing.js file. The file should configure at least app.routes and likely app.hosts. Add app.errors, app.dispatchers, and app.preheat if you are using those optional features.
Though routing.js may look a bit like a JSON configuration file, it's important to remember that it's really full JavaScript source! You can include any JavaScript code to dynamically configure your application's routing during the bootstrap process.
Reproduced below is the routing.js used in the "default" application template, demonstrating many of the main route type configurations, including how to chain and nest types. These will be explained in detail in the rest of this chapter.
app.routes = {
	'/*': [
		'manual',
		'templates',
		{
			type: 'cacheControl',
			mediaTypes: {
				'image/*': '1m',
				'text/css': '1m',
				'application/x-javascript': '1m'
			},
			next: {
				type: 'less',
				next: 'static'
			}
		}
	],
	'/example1/': '@example', // (dispatched)
	'/example2/': '/example/' // (captured)
}
​
app.hosts = {
	'default': '/myapp/'
}
In these settings, note that time durations are in milliseconds and data sizes in bytes. These can be specified as either numbers or strings. Examples: "1.5m" is 90000 milliseconds and "1kb" is 1024 bytes.

app.routes

Routes are configured in your application's routing.js, in the app.routes dict.

URI Templates

The keys of this dict are URI templates (see IETF RFC 6570), which look like URIs, but support the following two features:

Route Configurations

The values of the app.routes dict are route configurations. These are usually defined as JavaScript dicts, where the "type" key is the name of the route type configuration, and the rest of the keys configure the type. During the application's bootstrap process, these dicts are turned in instances of classes in the Prudence.Setup API namespace (the class names have the first character of the type capitalized). The values set in the route type configuration dict are sent to the class constructor.
All route types support the special "hidden" key, which if true specifies that the route is not part of the public URI-space. Prudence will always return a 404 error ("not found") for this match. Note that internal requests always bypass this mechanism, and so this functionality is useful if you want some URIs available in the internal URI-space but not the public one.
As a shortcut, you can just use a string value (the "type" name) instead of a full dict, however when used this way you must accept the default configuration. We will refer to this as the "short notation" of configuration.
Another useful shortcut: if the type starts with a "!", it is equivalent to setting the "hidden" key to true (this works in both long and short notations). Note that this is different from ending a capture target URI in "!", which would set the "hiddenTarget" key to true: see capture-and-hide.
There are also special alternate forms for some of the commonly used types, such as JavaScript arrays for the "chain" type. They are detailed below.
We will summarize all the route types briefly here, arranged according to usage categories, and will refer you to the API documentation for a complete reference. Note that some route type configurations allow nesting of further route type configurations.

Resource Route Types

These are routes to a single resource implementation.
"dispatch" or "@"
Use the "dispatch" type with an "id" param, or any string starting with the "@" character, to configure a dispatch mapping. For example, {type: 'dispatch', id: 'person'} is identical to '@person'. If you use "@", you can also optionally use a ":" to specify the "dispatcher" param, for example: "@profile:person" is identical to {type: 'dispatch', dispatcher: 'profile', id: 'person'}. If "dispatcher" is not specified, it defaults to "javascript". The unique ID should match a manual resource handled by your dispatcher, otherwise a 404 error ("not found") will result. The "dispatcher" param's value can be any key from the app.dispatchers dict. Handled by the Prudence.Setup.Dispatch class. See the manual resource guide for a complete discussion.
The "manual" route type is internally used by Prudence to handle the "dispatch" route type, via a server-side redirect. This introduces two special limitations on its use. First, it means that you must have a "manual" if you want to use "dispatch." Second, you must make sure the "manual" always appears before any use of "dispatch" in app.routes. For example, if you attach the manual to "/*" in a chain (as in the default application template), and you also want to add a "dispatch" to that chain, you need to put the "manual" before the "dispatch" in the chain. Otherwise, you might cause an endless server-side redirect, leading to a stack overflow error. Example of correct use:
app.routes = {
	'/*': [
		'manual',
		'@example', // must appear after the manual
		...
	],
	...
}
"hidden" or "!"
Use the "hidden" or "!" string values to hide a URI template. Prudence will always return a 404 error ("not found") for this match. Note that internal requests always bypass this mechanism, and so this functionality is useful if you want some URIs available in the internal URI-space but not the public one.
"resource" or "$…"
Use the "resource" type with a "class" param, or any string starting with the "$" character, to attach a Restlet ServerResource. For example, {type: 'resource', 'class': 'org.myorg.PersonResource'} is identical to '$org.myorg.PersonResource'. This is an easy way to combine Java-written Restlet libraries into your Prudence applications. Handled by the Prudence.Setup.Resource class.
"execute"
Use the "execute" type to attach a code execution resource. This powerful (and dangerous) resource executes all POST payloads as Scripturian templates. The standard output of the script will be returned as a response. Because it always execution of arbitrary code, you very likely do not want this resource publicly exposed. If you use it, make sure to protect its URL on publicly available machines! Handled by the Prudence.Setup.Execute class. The "execute" resource is very useful for debugging.
"status" or "!…"
Use the "status" type with a "code" param, or any number starting with a "!" character, to simply return an HTTP status code, doing nothing else. Useful for quick-and-dirty URI bindings. For example, "!401" would mark the URI as "not authorized" to all requests. Handled by the Prudence.Setup.Status class.

Mapping Route Types

You should use a wildcard URI template for all of these route types, because they work by processing the URI remainder.
"static"
Use the "static" type to create a static resource handler. By default uses the application's "/resources/" subdirectory chained to the container's "/libraries/web/" subdirectory for its "roots". Note that if you include it in a "chain" with "manual" and/or "templates", then "static" should be the last entry in the chain. Handled by the Prudence.Setup.Static class. See the static resources guide for a complete discussion.
"manual"
Use the "manual" type to create a manual resource handler. By default uses the application's "/resources/" subdirectory for its "root". Important limitation: All uses of this class in the same application share the same configuration. Only the first found configuration will take hold and will be shared by other instances. Handled by the Prudence.Setup.Manual class. See the manual resources guide for a complete discussion.
"templates"
Use the "templates" type to create a template resource handler. By default uses the application's "/resources/" subdirectory for its "root". Important limitation: All uses of this class in the same application share the same configuration. Only the first found configuration will take hold and will be shared by other instances. Handled by the Prudence.Setup.Templates class. See the template resources guide for a complete discussion.

Redirecting Route Types

"capture" or "/…"
Use the "capture" type with a "uri" param, or any string starting with the "/" character, to configure a capture. For example, {type: 'capture', uri: '/user/profile/'} is identical to '/user/profile/'. Note that adding a "!" character at the end of the URI (not considered as part of the actual target URI) is a shortcut for also hiding the target URI. Capturing-and-hiding is indeed a common use case. Handled by the Prudence.Setup.Capture class. See resource capturing for a complete discussion.
"redirect" or ">…"
Use the "redirect" type with a "uri" param, or any string starting with the ">" character, to asks the client to redirect (repeat its request) to a new URI. For example, {type: 'redirect', uri: 'http://newsite.org/user/profile/'} is identical to '>http://newsite.org/user/profile/'. Handled by the Prudence.Setup.Redirect class. See the web data guide for a complete discussion, as well as other options for redirection.
"addSlash"
Use the "addSlash" type for a permanent client redirect from the URI template to the original URI with a trailing slash added. It's provides an easy way to enforce trailing slashes in your application. Handled by the Prudence.Setup.AddSlash class.

Combining Route Types

"chain" or "[…]"
Use the "chain" type with a "restlets" param (a JavaScript array), or just a JavaScript array, to create a fallback chain. The values of the array can be any route type configuration, allowing for nesting. They will be tested in order: the first value that doesn't return a 404 ("not found") error will have its value returned. This is very commonly used to combine mapping types, for example: ['manual', 'templates', 'static']. Handled by the Prudence.Setup.Chain class.
"router"
Use the "router" type with a "routes" param (a JavaScript dict) to create a router. The values of the dict can be any route type configuration, allowing for nesting. This is in fact how Prudence creates the root router (app.routes). Handled by the Prudence.Setup.Router class.

Filtering Route Types

All these route types require a "next" param for nesting into another route type. See the filtering guide for a complete discussion.
"filter"
Use the "filter" type with the "library" and "next" params to create a filter. "library" is the document name (from the application's "/libraries/" subdirectory), while "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.Filter class.
"injector"
Use the "injector" type with the "locals" and "next" params to create an injector. An injector is a simple filter that injects preset valued into conversation.locals, but otherwise has no effect on the conversation. This is useful for inversion of control (IoC): you can use these conversation.locals to alter the behavior of nested route types directly in your routing.js. Handled by the Prudence.Setup.Injector class.
"basicHttpAuthenticator"
Use the "basicHttpAuthenticator" with the "credentials", "realm" and "next" params to require HTTP authentication before allow the request to go through. This straightforward (but weak and inflexible) security mechanism is useful for ensuring that robots, such as search engine crawlers, as well as unauthorized users do not access a URI. Handled by the Prudence.Setup.BasicHttpAuthenticator class. See the HTTP authentication guide for a complete discussion.
"cacheControl"
Use the "cacheControl" type with a "next" param to create a cache control filter. "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.CacheControl class. See the static resources guide for a complete discussion.
"cors"
Use the "cors" type with a "next" param to create a Cross-Origin Resource Sharing (CORS) filter. "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.Cors class. See the CORS guide for a complete discussion.
"javaScriptUnifyMinify"
Use the "javaScriptUnifyMinify" type with a "next" param to create a JavaScript unify/minify filter. "roots" defaults to your application's "/resources/scripts/" and your container's "/libraries/web/scripts/" subdirectories. "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.JavaScriptUnifyMinify class. See the static resources guide for a complete discussion.
"cssUnifyMinify"
Use the "cssScriptUnifyMinify" type with a "next" param to create a CSS unify/minify filter. "roots" defaults to your application's "/resources/style/" and your container's "/libraries/web/style/" subdirectories. "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.CssUnifyMinify class. See the static resources guide for a complete discussion.
"less"
Use the "less" type with a "next" param to create a LESS compiling filter. "roots" defaults to your application's "/resources/style/" and your container's "/libraries/web/style/" subdirectories. "next" is any route type configuration, allowing for nesting. Handled by the Prudence.Setup.Less class. See the static resources guide for a complete discussion.

Custom Route Types

With some knowledge of the Restlet library, you can easily create your own custom route types for Prudence:
  1. Create a JavaScript class that:
    1. Implements a create(app, uri) method. The "app" argument is the instance of Prudence.Setup.Application, and the "uri" argument is the URI template to which the route type instance should be attached. The method must return an instance of a Restlet subclass.
    2. Accepts a single argument, a dict, to the constructor. The dict will be populated by the route type configuration dict in app.routes.
  2. Add the class to Prudence.Setup. Remember that the class name begins with an uppercase letter, but will begin with a lowercase letter when referenced in app.routes.
If you like, you can use Sincerity.Classes to create your class (you don't have to), and also inherit from Prudence.Setup.Restlet.
Here's a complete example in which we implement a route type, named "see", that redirects using HTTP status code 303 ("see other"). (Note this same effect can be better achieved using the built-in "redirect" route type, and is here intended merely as an example.)
document.require('/sincerity/classes/')
​
Prudence.Setup.See = Sincerity.Classes.define(function() {
	var Public = {}
​
	Public._inherit = Prudence.Setup.Restlet
	Public._configure = ['uri']
​
	Public.create = function(app, uri) {
		importClass(org.restlet.routing.Redirector)
		var redirector = new Redirector(app.context, this.uri, Redirector.MODE_CLIENT_SEE_OTHER)
		return redirector
	}
​
	return Public
}())
​
app.routes = {
	...
	'/original-uri/': {type: 'see', uri: 'http://newsite.org/new-uri/'}
}

Two Routing Paradigms

Prudence offers three built-in techniques for you to support a URI or a URI template, reflecting two different routing paradigms:
  1. Resource mapping (page 1): The filesystem hierarchy under an application's "/resources/" subdirectory is directly mapped to URIs (but not URI templates). Both directory- and file-names are mapped in order of depth. By default, Prudence hides filename extensions from the published URIs, but uses these extensions to extracts MIME-type information for the resources. Also, mapping adds trailing slashes by default, by redirecting URIs without trailing slash to include them (on the client's side). Filesystem mapping provides the most "transparent" management of your URI-space, because you do not need to edit any configuration file: to change URIs, you simply move or rename files and directories.
  2. URI/resource separation:
    1. Resource capturing. This use case does not belong to the URI/resource separation paradigm.
    2. Resource dispatching (page 1): In your application's routing.js you can map URIs or URI templates to a custom ID, which is then dispatched to your resource handling code. Dispatching provides the cleanest and most flexible separation between URIs and their implementation.
When embarking on a new project, you may want to give some thought as which paradigm to use. Generally, URI/resource separation is preferred for larger applications because it allows you more choices for your code organization. However, it does add an extra layer of configuration, and the URI-space is not as transparent as it is for resource mapping. It may make sense to use both paradigms in the same application where appropriate. Read on, and make sure you understand how to use all three routing techniques.

Resource Mapping

Resource mapping is the most straightforward and most familiar technique and paradigm to create your URI-space. It relies on a one-to-one mapping between the filesystem (by default files under your application's "/resources/" subdirectory) to the URI-space. This is how static web servers, as well as the PHP, JSP and ASP platforms usually work.
Prudence differs from the familiar paradigm in three ways:
  1. For manual and template resources, Prudence hides filename extensions from the URIs by default. Thus, "/resources/myresource.m.js" would be mapped to "/resources/myresource/". The reasons are two: 1) clients should not have to know about your internal implementation of the resource, and 2) it allows for cleaner and more coherent URIs. Note the filename extensions are used internally by Prudence (differently for manual and template resources). Note that this does not apply to static resources: "/resources/images/logo.png" will be mapped to "/images/logo.png".
  2. For manual and template resources, Prudence by default requires trailing slashes for URIs. If clients do not include the trailing slash, they will receive a 404 ("not found") error. Again, the reasons are two: 1) it makes relative URIs always unambiguous, which is especially relevant in HTML and CSS, and 2) it clarifies the extent of URI template variables. As a courtesy to sloppy clients, you can manually add a permanent redirection to a trailing slash, using the "addSlash" route type. For example:
    app.routes = {
    	...
    	'/main', 'addSlash',
    	'/person/profile/{id}': 'addSlash'
    }
    
  3. This mapped URI-space can be manipulated using URI hiding and capturing, allowing you to support URI templates and rewrite URIs.

Mapping URI Templates

The problem with resource mapping is that the URIs are "static": they are only and exactly the the directory and file path. However, this limitation is easily overcome by Prudence's "capturing" mechanism, which works on URI templates. For example, let's say you have a template resource file at "/resources/user/profile.t.html", but instead of it being mapped to the URI "/user/profile/", you want to access it via a URI template: "/user/profile/{userId}/":
app.routes = {
	...
	'/user/profile/{userId}/': '/user/profile/'
}
A URI such as "/user/profile/4431/" would then be internally redirected to the "/user/profile/" URI. Within your "profile.t.html" file, you could then access the captured value as conversation.locals:
<html>
<body>
<p>
User profile for user <%= conversation.locals.get('userId') %>.
</p>
</body>
</html>
We've used a template resource in this example, but capturing can be used for both template and manual resources. The same conversation.locals API is used in both cases.
Capture-and-Hide
You may also want to make sure that "/user/profile/" cannot be accessed without the user ID. To capture and hide together you can use the shortcut notation:
app.routes = {
	...
	'/user/profile/{userId}/': '/user/profile/!'
}
That final "!" is equivalent to setting "hiddenTarget: true" in the long notation. You may also configure capturing and hiding separately, using the "hidden" route type. The following is equivalent to the above:
app.routes = {
	...
	'/user/profile/{userId}/': '/user/profile/',
	'/user/profile/': '!'
}

Dynamic Capturing

URI capturing can actually do more than just capture to a single URI: the target URI for a capture is, in fact, also a URI template, and can include any of the conversation attributes discussed in the string interpolation guide. For example:
app.routes = {
	...
	'/user/{userId}/preferences/': '/database/preferences/{m}/?id={userId}'
}
The request method name would then be interpolated into the "{m}", for example it could be "GET" or "POST". It would thus capture to different target URIs depending on the request. So, you could have "/database/preferences/GET.html" and "/database/preferences/POST.html" files in your "/resources/" subdirectory to handle different request methods.
Note that it's also possible to dynamically capture and interpolate the wildcard, for example:
app.routes = {
	...
	'/user/*': '/database/user/?id={rw}'
}
Dynamic Capture-and-Hide
Note that if you use the "!" capture-and-hide trick with dynamic capturing, Prudence will hide any URI that matches the template. For example:
app.routes = {
	...
	'/user/{userId}/preferences/': '/database/preferences/{m}/!'
}
Here, "/database/preferences/GET/" is hidden, but also "/database/preferences/anything/", etc. If you do not want this behavior, then you should explicitly hide specific URIs instead:
app.routes = {
	...
	'/user/{userId}/preferences/': '/database/preferences/{m}/',
	'/database/preferences/GET/': '!',
	'/database/preferences/POST/': '!'
}

Limitations of Resource Mapping

While resource mapping is very straightforward—one file per resource (or per type of resource if you capture URI templates)—it may be problematic in three ways:
  1. In large URI-spaces you may suffer from having too many files. Though you can use "/libraries/" to share code between your resources, mapping still requires exactly one file per resource type.
  2. Mapped manual resources must have all their entry points (handleInit, handleGet, etc.) defined as global functions. This makes it awkward to use object oriented programming or other kinds of code reuse. If you define your resources as classes, you would have to hook your class instance via the global entry points.
  3. The URI-space is your public-facing structure, but your internal implementation may benefit from an entirely different organization. For example, some resources my be backed by a relational database, others by a memory cache, and others by yet another subsystem. It may make sense for you to organize your code according to subsystems, rather than the public URI-space. For this reason, you would want the URI-space configuration to be separate from your code organization.
These problems might not be relevant to your application. But if they are, you may prefer the URI/resource separation paradigm, which can be implemented via resource capturing or dispatching, documented below.

URI/Resource Separation

Resource Capturing

Resource capturing, for the purpose of the URI/resource separation paradigm, only makes sense for template resources. For manual resources, resource dispatching provides a similar structural function.
Resource capturing lets you use any public URI for any library template resource. For example, let's assume that you have the following files in "/libraries/includes/": "/database/profile.html", "/database/preferences.html" and "/cache/session.html", which you organized in subdirectories according to the technologies used. Your URI-space can be defined thus, using the "capture" route type:
app.routes = {
	...
	'/user/{userId}/preferences/': '/database/preferences/',
	'/user/{userId}/profile/': '/database/profile/',
	'/user/{userId}/session/': '/cache/session/'
}
Note how the URI-space is organized completely differently from your filesystem: we have full URI/resource separation.
Under the hood: Prudence's capturing mechanism is implemented as server-side redirection (sometimes called "URI rewriting"), with the added ability to use hidden URIs as the destination. It's this added ability that makes capturing useful for URI/resource separation: hidden URIs include both template resource files in your application's "/libraries/includes/" subdirectory as well as URIs routed to the "hidden" route type.

Resource Dispatching

Resource dispatching, for the purpose of the URI/resource separation paradigm, only makes sense for manual resources. For template resources, resource capturing provides a similar structural function.
Configuring a dispatch is straightforward. In routing.js, use the "dispatch" route type, or the "@" shortcut:
app.routes = {
	...
	'/session/{sessionId}/': '@session',
	'/user/{userId}/preferences/': '@user'
}
The long-form notation, with all the settings at their defaults, would look like this:
app.routes = {
	...
	'/session/{sessionId}/': {
		type: 'dispatch',
		id: 'session',
		dispatcher: null,
		locals: []
	}
}
Note that, similarly to capturing, you can interpolate conversation attributes into the ID. For example, here we will automatically use a different dispatch ID according the protocol, either "session.HTTP" or "session.HTTPS":
app.routes = {
	...
	'/session/{sessionId}/': '@session.{p}'
}
The Dispatch Map
By default, to implement your dispatched resources, create a library named "/dispatched/", which is expected to change a global dict named "resources". That dict maps IDs to implementations.
For our example, let's create a "/libraries/dispatched.js" file:
var UserResource = function() {
	this.handleInit = function(conversation) {
		conversation.addMediaTypeByName('text/plain')
	}
​
	this.handleGet = function(conversation) {
		return 'This is user #' + conversation.locals.get('userId')
	}
}
​
resources = {
	session: {
		handleInit: function(conversation) {
			conversation.addMediaTypeByName('text/plain')
		},
		handleGet: function(conversation) {
			return 'This is session #' + conversation.locals.get('sessionId')
		}
	},
	user: new UserResource()
}
We've mapped the "session" dispatch ID to a dict, and used simple JavaScript object-oriented programming for the "user" dispatch ID. (Note that the Sincerity.Classes facility offers a comprehensive object-oriented system for JavaScript, but we preferred more straightforward code for this example.)
As you can see, the resources.js file does not refer to URIs, but instead to dispatch IDs, which you can dispatch as you see fit. This is true URI/resource separation.
These defaults are all configurable: see app.dispatchers for more information.
Other Programming Languages
Resource dispatching is also supported for Python, Ruby, PHP, Lua, Groovy and Clojure, via alternate dispatchers. To use them, you must specify the dispatcher, which is simply the name of the language in lowercase, when you configure the dispatch. For example:
app.routes = {
	...
	'/session/{sessionId}/': {
		type: 'dispatch',
		id: 'session',
		dispatcher: 'python'
	}
}
You can also use the "@" shortcut like so:
app.routes = {
	...
	'/session/{sessionId}/': '@python:session'
}

Inversion of Control (IoC)

Object-oriented inheritance is one useful way to reuse code while allowing for special implementations. Additionally, Prudence allows for a straightforward inversion of control mechanism.
For both capturing and dispatching, you can inject set values to conversation.locals. You would need to use the long-form notation to do this. Here are examples for both a capture and a dispatch:
app.routes = {
	...
	'/user/{userId}/': {type: 'capture', uri: '/user/', locals: {style: 'simple'}},
	'/user/{userId}/full/': {type: 'capture', uri: '/user/', locals: {style: 'full'}},
	'/user/{userId}/preferences/': {type: 'dispatch', id: 'user', locals: {section: 'preferences'}},
	'/user/{userId}/profile/: {type: 'dispatch', id: 'user', locals: {section: 'profile'}}
}
Note that in each case two URI templates are captured/matched to the exact same resource, but the "locals" dict used is different for each. In your resource implementations, you can then allow for different behavior according to the value of the set conversation.local. For example:
this.handleGet = function(conversation) {
	var section = conversation.locals.get('section')
	if (section == 'preferences') {
		...
	}
	else if (section == profile') {
		...
	}
}
This allows you to configure your resources in routing.js, rather than at their implementation code. In other words, "control" is "inverted," via value injection.

Pure URI/Resource Separation

The default routing.js makes all the resource types public, and chained to the root URI. At its simplest, it looks like this:
app.routes = {
	'/*': [
		'manual',
		'templates',
		'static'
	]
}
However, if you want complete control over URI/Resource separation, you can avoid having these public by hiding them at specific URIs:
app.routes = {
	'/_templates/*': '!templates',
	'/_manual/*': '!manual',
	'/_static/*': '!static',
​
	'/style/*' : '/_static/style/{rw}',
	'/*': '/_templates/page/?id={rw}'
}
With the above routing.js, we can then specify exactly which URIs go where, with nothing made public by default. The "_" prefixes are merely a convention in this case to specify an internal-only URI.

app.errors

By default, Prudence will display ready-made error pages if the response's HTTP status code is an error (>=400), but you can override these by settings your own custom pages:
app.errors = {
	404: '/errors/not-found/',
	500: '/errors/fail/'
}
The keys of the dict are status codes, while the values work like captures. This means that you can implement your error pages using any kind of resource: manual, template or static.
If your error resource is mapped under "/resources/", and you don't want it exposed, use the capture-and-hide notation:
app.errors = {
	404: '/errors/not-found/!'
}
This is equivalent to explicitly hiding the URI in app.routes using the "hidden" route type:
app.routes = {
	...
	'/errors/not-found/': '!'
}
Note that 500 ("internal server error") statuses caused by uncaught exceptions can be handled specially by enabling debug mode.
Warning: If you decide to implement your error pages using a non-static resource, you need to take two things into account. For 404 errors, you must have the resource type handling the page be the first handler in a chain in app.routes. For example, if you are using a template resource, then you must have "templates" first. The reason is that a chain works internally by detecting 404 errors and moving on to the next one: if the first one returns a 404 again, this will result in a recursion and will throw a 500 exception. Second, for any non-static error resource, you want to be very sure that your code there does not throw an exception. If that happens, it would cause a 500 status code, but if the original error was not 500, the result would confuse the user and complicate debugging. However, if the original status code was 500, then it could be much worse: the error would trigger your error resource to be displayed again, which might throw the exception again… resulting in a stack overflow error. Due to these pitfalls, it's probably a good idea to implement your error pages as static resources.
It is also possible to set error captures for all applications by configuring them into the component. In such a case, if applications configure their own error captures, those would override the component-wide configuration.

app.hosts

Use app.hosts to assign the application to a base URI on one or more virtual hosts.
The default configuration uses a single host, the "default" one, but you can add more, or even not have a single "default" host. Still, note that only a single application instance is used, even if attached to multiple hosts: for example, all application.globals are shared no matter which host a request is routed from.
To configure your hosts, and for a more complete discussion, see the component configuration guide.

The Bare Minimum

You need to attach your application to at least one host to make it public.
app.hosts = {
	'default': '/myapp/'
}
(Note the required use of quotes around "default", due to it being a reserved keyword in JavaScript.)
If you don't have an app.hosts definition, or if it is empty, then your application will not be publicly available over HTTP. However, it will still run, and be available as an internal API.

The Internal Host

"internal" is a reserved host name, used to represent the internal URI-space.
By default, applications are always attached to the "internal" host with the base URI being the application's subdirectory name. However, you can override this default should you require:
app.hosts = {
	'default': '/myapp/',
	internal: '/special/'
}

Multiple Hosts

Here's an example of attaching the app to two different virtual hosts, with different base URIs under each:
app.hosts = {
	'default': '/myapp/',
	'privatehost': '/admin/'
}
If you need your application to sometimes behave differently on each host, use the conversation.host API. Note that it will be null when routed from the internal host. Example:
var host = conversation.host
if (Sincerity.Objects.exists(host) && (host.name == 'privatehost')) {
	...
}

app.dispatchers

This section is optional, and is used to change the way your application's dispatching works.

Setting the Default Dispatcher

As seen above in resource dispatching, if you you do not specify the dispatcher when configuring a "dispatch" route type, it will default to the "javascript" dispatcher. You may change the default like so:
app.routes = {
	'/session/{sessionId}/': '@session'
}
​
app.dispatchers = {
	'default': 'python'
}
In the above, our "@session" dispatch will be using the "python" dispatcher.

Setting the Dispatch Map

We've also seen that by default the dispatcher will attempt to execute your "/dispatched/" library in order to initialize the dispatch map. However, you may change this location per dispatcher like so:
app.dispatchers = {
	javascript: '/mylib/mydispatchmap/'
}
This is especially useful if you're using more than one dispatcher in your routing, because each dispatcher would need its own resource map. For example:
app.routes = {
	...
	'/user/{userId}/': '@user',
	'/session/{sessionId}/': '@python:session',
	'/page/{pageId}/': '@groovy:page'
}
​
app.dispatchers = {
	javascript: '/mylib/javascript-dispatchmap/',
	python: '/mylib/python-dispatchmap/',
	groovy: '/mylib/groovy-dispatchmap/'
}

Custom Dispatchers

Custom dispatchers are very useful for integrating alternative templating engines into Prudence.
Under the hood, resource dispatching is handled by the URI capturing mechanism: the URI is captured to a special manual resource—the "dispatcher"—with an injected value specifying the ID of resource to which it should dispatch.
Prudence's default dispatchers can be found in the "/libraries/scripturian/prudence/dispatchers/" directory of your container. For example, the JavaScript dispatcher is "/libraries/scripturian/prudence/dispatchers/javascript.js". You are encouraged to look at the code there in order to understand how dispatching works: it's quite straightforward delegation of the entry points of a manual resource.
However, you can also write your own dispatchers to handle different dispatching paradigms. To configure them, you will need to use a long-form for app.dispatchers. For example, here we override the default "javascript" dispatcher:
app.dispatchers = {
	...
	special: {
		dispatcher: '/dispatchers/special-dispatcher/',
		customValue1: 'hello',
		customValue2: 'world'
	}
}
The dispatcher code (a standard manual resource) would be in a "/libraries/dispatchers/special-dispatcher.js" file under your application's subdirectory. You would be able to access the dispatch ID there as the injected "prudence.dispatcher.id" conversation.local. "customValue1" and "customValue2" would be application.globals: "prudence.dispatcher.special.customValue1" and "prudence.dispatcher.special.customValue2" respectively.
You can also override the default dispatchers:
app.dispatchers = {
	...
	javascript: {
		dispatcher: '/dispatchers/my-javascript-dispatcher/',
		resources: '/resources/'
	}
}
See the section on integrating alternative templating engines for a complete example.

app.preheat

When a resource gets hit by a request for the first time, there will likely be an initial delay. Your code may have to be compiled, or, if it has been cached, would at least have to be loaded and initialized. But all that should happen very fast: the more serious delay would be caused by initializing subsystems and libraries, such as connecting to databases, logging in to external services, etc.
Another source for delay is that, if you are caching pages, as you very well should, then the some cached pages may not exist or be old. The first hit would thus need to generate and cache the page, which is much slower than using the cached version. For very large applications optimized for caching, a "cold" cache can cause serious problems: see the discussion in Scaling Tips.
To avoid the delay, it's recommended that you ready your resources by hitting them as soon as Prudence starts up. This happens in two phases:
Your app.preheat is simply an array of relative URIs. As an example, let's preheat the homepage and a few specific resources:
app.preheat = [
	'/',
	'/user/x/',
	'/admin/'
]
Note that you can't use URI templates in app.preheat, only explicit URIs. Thus, if you have routed a "/user/{name}/" URI template, you would have to "fill in" the template with a value. In our example, we chose "/user/x/". Also note that because preheats are internal requests you can use this mechanism to preheat hidden URIs.
Smart use of app.preheat can very effective, and it's very easy to use. Note that you may also use the startup task for your own custom preheating.
Both defrosting and preheating are handled in a thread pool, so that they can finish as quickly as possible. Learn how to configure it here. The duration of the complete process will be announced when you start Prudence. For example:
Executing 3488 startup tasks...
Finished all startup tasks in 1.432 seconds.

Understanding Routing

In this final section, we'll describe in detail how routing works in Prudence. It can be considered optional, advanced reading.
In Prudence, "routing" refers to the decision-making process by which an incoming client request reaches its server-side handler. Usually, information in the request itself is used to make the decision, such as the URI, cookies, the client type, capabilities and geolocation. But routing can also take server-side and other circumstances into account. For example, a round-robin load-balancing router might send each incoming request to a different handler in sequence.
A request normally goes through many route types before reaching its handler. Filters along the way can change information in the request, which could also affect routing, and indeed filters can be used as routing tools.
This abstract, flexible routing mechanism is one of Prudence's most powerful features, but it's important to understand these basic principles. A common misconception is that routing is based on the hierarchical structure of URIs, such that a child URI's routing is somehow affected by its parent URI. While it's possible to explicitly design your routes hierarchically, routing is primarily to be understood in terms of the order of routers and filters along the way. A parent and child URI could thus use entirely different handlers.
To give you a better understanding of how Prudence routing works, let's follow the journey of a request, starting with routing at the server level.
Step 1: Servers
Requests come in from servers. Each server listens at a particular HTTP or HTTPS port, and multiple servers may in turn be restricted to particular network interfaces on your machine. By default, Prudence has a single server that listens to HTTP requests on port 8080 coming in from all network interfaces.
Step 2: The Component
There is only one component per Prudence instance, and all servers route to it. This allows Prudence a unified mechanism to deal with all incoming requests.
Step 3: Virtual Hosts
The component's router decides which virtual host should receive the request. The decision is often made according to the domain name in the URL, but can also take into account which server it came from. Virtual hosting is a tool to let you host multiple sites on the same Prudence instance, but it can be used for more subtle kinds of routing, too.
At the minimum you must have one virtual host. By default, Prudence has one that accepts all incoming requests from all servers. If you have multiple servers and want to treat them differently, you can create a virtual host for each.
Step 4: Applications
Using app.hosts, you can configure which virtual hosts your application will be attached to, as well as the base URI for the application on each virtual host. An application can be configured to accept requests from several virtual hosts.
To put it another way, there's a many-to-many relationship between virtual hosts and applications: one host can have many applications, and the same application can be attached to many hosts.
Note that you can create a "nested" URI scheme for your applications. For example, one application might be attached at the root URI at a certain virtual host, "/", while other applications might be at different URIs beneath the root, "/cms/" and "/cms/support/forum/". The root application will not "steal" requests from the other applications, because the request is routed to the right application by the virtual host. The fact that the latter URI is the hierarchical descendant of the former makes no difference to the virtual host router.
A Complete Route
Let's assume a client from the Internet send a request to URI "http://www.wacky.org/cms/support/forum/thread/12/."
Our machine has two network interfaces, one facing the Internet and one facing the intranet, and we have two servers, one for each network adapter. This particular request has come in through the external server. The request then reaches the component's router.
We have a few virtual hosts: one to handle "www.wacky.org", our organization's main site, and another to handle "support.wacky.org", a secure site where registered users can open support tickets.
Our forum application (in the "/applications/forum/" subdirectory) is attached to both virtual hosts, but at different URIs. It's at "www.wacky.org/cms/support/forum/" and at "support.wacky.org/forum/". In this case, our request is routed to the first virtual host. Though there are a few applications installed at this virtual host, our request follows the route to the forum application.
The remaining part of the URI, "/thread/12/" will be further routed inside the forum application, according to route types installed in its routing.js.

The Prudence Manual is provided for you under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. The complete manual is available for download as a PDF.

Download manual as PDF Creative Commons License