logo

WebApp

Overview

WARNING: the webapp framework is still an early prototype, so will be going through many changes during development

The webapp pod defines a framework for building web applications by assembling prebuilt WebSteps:

  • FindResourceStep: maps the request URI to a Fan obj which represents a resource in the VM's local namespace
  • FindViewStep: find a suitable Weblet which can service the request and provide a representation of the resource
  • FindChromeStep: lets you plug in a common look and feel across all your views
  • ServiceViewStep: does it
  • LogStep: logs using W3C extended log format

FindResourceStep

FindResourceStep is responsible for mapping the web request URI to a Fan object which represents the the resource to service. This object can be anything, but is typically a File or an object in the domain model (such as a row in the database). In most cases, the web request URI is mapped directly to the local namespace via Sys.ns. But FindResourceStep also provides the following features:

  • Defines the home page resource
  • Searches for file extensions
  • Searches for the index file to use for a directory
  • Redirects to use trailing slash on directories
  • Returns 404 if resource isn't found

Let's take an example:

// pipeline step config
FindResourceStep
{
  extSearch = ["fan", "html", "txt"].toImmutable
  dirIndex  = ["index.fan", "index.html"].toImmutable
}

// setup
Sys.ns.create(`/homePage`, scriptDir + `home.html`)
Sys.mount(`/dir`, Namespace.makeDir(scriptDir + `dir/`))

// application directory
boot.fan
home.html
dir/
  index.fan
  subdir/
    index.html
    script.fan
    test.txt

Since we didn't configure the homePage field, it defaults to "/homePage", which is the resource object we'll use for servicing "/". In our setup we map "/homePage" to the "home.html" file in the same directory as our boot script.

Since we configured extSearch, we can use the following URIs with or without extensions:

/dir/index              =>  /dir/index.fan
/dir/index.fan          =>  /dir/index.fan
/dir/subdir/script      =>  /dir/subdir/script.fan
/dir/subdir/script.fan  =>  /dir/subdir/script.fan
/dir/subdir/test        =>  /dir/subdir/test.txt
/dir/subdir/test.txt    =>  /dir/subdir/test.txt

When processing directories we use the dirIndex field to search the directory for its index file. We also check if the web request is accessing a directory URI without a trailing slash, in which case we do a redirect to keep relative hrefs working:

/dir          =>  redirects to /dir/
/dir/         =>  /dir/index.fan
/dir/subdir   =>  redirects to /dir/subdir/
/dir/subdir/  =>  /subdir/index.html

If you want your own resource objects to take advantage of the trailing slash redirect, you need only declare a isDir() method which return true.

FindViewStep

FindViewStep is responsible for finding a Weblet to service the request by returning an appropriate representation of the resource found by FindResourceStep.

If the resource is itself a Weblet, then the view is the resource itself. Otherwise the type database is queried for a type which declares itself a "webView" on the resource type. For example:

@webView=Invoice.type
class InvoiceView : Weblet {}

File resources are automatically handled by the web::FileWeblet which handles all the dirty details for cache control, modification time, ETags, etc.

FindChromeStep

FindChromeStep is used to create a pluggable look and feel or theme for a web application. The chrome is just a normal webapp::Widget which wraps the view Widget. If the view isn't a Widget, then the chrome has no effect.

ServiceViewStep

ServiceViewStep class is a simple class which calls Weblet.service on the view weblet.

LogStep

LogStep class is used to generate a server log file for all HTTP requests in the W3C Extended Log File Format. The file Uri must be configured - records are always appended to this file. Logging is done on the onAfterService callback.

The fields property configures the format of the log records. It is a string of field names separated by a space. The following field names are supported:

  • date: UTC date as DD-MM-YYYY
  • time: UTC time as hh:mm:ss
  • cs-method: the request method such as GET
  • cs-uri: the encoded request uri (path and query)
  • cs-uri-stem: the encoded path of the request uri
  • cs-uri-query: the encoded query of the request uri
  • sc-status: the return status code
  • time-taken: the time taken to process request in milliseconds
  • cs(HeaderName): request header value such

If any unknown fields are specified or not available then "-" is logged. The default format is:

date time cs-method cs-uri-stem cs-uri-query
  sc-status time-taken cs(User-Agent) cs(Referrer)

Example log record with this format:

09-04-2008 01:19:07 - GET /dir/index - 200 85 "Mozilla/5.0 (Windows; U;
  Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13" -