const mixinafBedSheet::FileHandler

afBedSheet::FileHandler

(Service) - A Route Handler that maps URLs to files on the file system.

Suppose your project has this directory structure:

myProj/
 |-- fan/
 |-- test/
 `-- etc
      `-- static-web/
           |-- css/
           |    `-- app.css
           |-- images/
           |    `-- logo.png
           `-- scripts/

Then to map the css/ dir add the following to AppModule:

@Contribute { serviceType=FileHandler# }
static Void contributeFileHandler(Configuration conf) {
  conf[`/stylesheets/`] = `etc/static-web/css/`.toFile
}

Browsers may then access app.css with the URL /stylesheets/app.css.

Rather than hardcoding /stylesheets/app.css in the HTML, it is better to generate a client URL from FileHandler.

url := fileHandler.fromLocalUrl(`/stylesheets/app.css`).clientUrl

Most of the time url will be the same as the hardcoded URL but it has the added benefit of:

  • Failing fast if the file does not exist
  • generating correct URLs in non-root WebMods
  • using asset caching strategies

The generated clientUrl contains any extra WebMod path segments required to reach the BedSheet WebMod. It also contains path segments as provided by any asset caching strategies, such as Cold Feet.

Serve All Root Directories

Using the above example, extra config would need to be added to serve the images/ and the scripts/ directories. This is not ideal. So to serve all the files and directories under etc/static-web/ add config for the root URL:

conf[`/`] = `etc/static-web/`.toFile

This way everything under etc/static-web/ is served as is. Example, logo.png is accessed with the URL /images/logo.png.

Fail Fast

An understated advantage of using FileHandler to generate client URLs for your assets is that it fails fast.

Should an asset not exist on the file system (due to a bodged rename, a case sensitivity issue, or other) then FileHandler will throw an Err on the server when the client URL is constructed. This allows your web tests to quickly pick up these tricky errors.

The lesser appealing alternative is for the incorrect URL to be served to the browser which on following, will subsequently receive a 404 - Not Found. While this may not seem a big deal, these errors often go unnoticed and easily find their way into production.

Precedence with Other Routes

The FileHandler directory mappings are automatically added to the Routes service on startup. That means it is possible to specify a Route URL with more than one handler; a custom handler and this FileHandler. With a bit of configuration it is possible to specify which takes precedence.

The FileHandler route contributions are set with the ID afBedSheet.fileHander, so when Route precedence is important, use it in your config:

@Contribute { serviceType=Routes# }
static Void contributeRoutes(Configuration config) {

  // this Route will be served in place of the file 'url1.txt'
  config.set("beforeExample", Route(`/url1.txt`, ...)).before("afBedSheet.fileHandler")

  // this Route will be served if there is no file called 'url2.txt'
  config.set("afterExample", Route(`/url2.txt`, ...)).after("afBedSheet.fileHandler")
}

@uses Configuration of Uri:File

directoryMappings

Source

abstract Uri:File directoryMappings()

Returns the map of URL to directory mappings

fromLocalUrl

Source

abstract FileAsset fromLocalUrl(Uri localUrl, Bool checked := true)

Given a local URL (a simple URL relative to the WebMod), this returns a corresponding (cached) FileAsset.

url := fileHandler.fromLocalUrl(`/stylesheets/app.css`).clientUrl

Throws ArgErr if the URL is not mapped. Throws ArgErr if checked and the file does not exist.

fromServerFile

Source

abstract FileAsset fromServerFile(File serverFile, Bool checked := true)

Given a file on the server, this returns a corresponding (cached) FileAsset.

Throws ArgErr if the file directory is not mapped. Throws ArgErr if checked and the URL does not exist.

serviceRoute

Source

abstract FileAsset? serviceRoute(Uri remainingUrl)

The (boring) Route handler method. Returns a FileAsset as mapped from the HTTP request URL or null if not found.