Operator

The CLI has three subcommands:

  1. eval evaluates a handlebars template from STDIN.
  2. get renders content from a content directory.
  3. serve starts an HTTP server.

serve is where the real action is, but the other two come in handy at times.

These commands all require a content directory, which is just the folder where your website lives. There are a bunch of sample content directories in the repository.

To learn more, use the --help option (alone or with a subcommand):

operator --help
A web server for static and dynamic content

Usage: operator [OPTIONS] <COMMAND>

Commands:
  eval   Evaluates a handlebars template from STDIN
  get    Renders content from a content directory
  serve  Starts an HTTP server
  help   Print this message or the help of the given subcommand(s)

Options:
  -q, --quiet       Silence all output
  -v, --verbose...  Verbose mode; multiple -v options increase the verbosity
  -h, --help        Print help
  -V, --version     Print version
operator eval --help
Evaluates a handlebars template from STDIN

Usage: operator eval [OPTIONS] --content-directory <path>

Options:
      --content-directory <path>
          Path to a directory containing content files.
          
          Files in this directory can be referenced from the provided handlebars
          template.

  -q, --quiet
          Silence all output

      --query <query-string>
          Optional query parameters.
          
          This uses the same format as HTTP requests (without a leading "?"). For
          example: --query="a=1&b=2".

  -v, --verbose...
          Verbose mode; multiple -v options increase the verbosity

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
operator get --help
Renders content from a content directory

Usage: operator get [OPTIONS] --content-directory <path> --route <route>

Options:
      --content-directory <path>
          Path to a directory containing content files.
          
          The route argument refers to files within this directory.

  -q, --quiet
          Silence all output

      --route <route>
          Route specifying which piece of content to get.
          
          Routes are extension-less slash-delimited paths rooted in the content
          directory. They must begin with a slash.

  -v, --verbose...
          Verbose mode; multiple -v options increase the verbosity

      --query <query-string>
          Optional query parameters.
          
          This uses the same format as HTTP requests (without a leading "?"). For
          example: --query="a=1&b=2".

      --accept <media-range>
          Declares what types of media are acceptable as output.
          
          This serves the same purpose as the HTTP Accept header: to drive content
          negotiation. Unlike the Accept header it is only a single media range.
          Defaults to "*/*".

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
operator serve --help
Starts an HTTP server

Usage: operator serve [OPTIONS] --content-directory <path> --bind-to <socket-address>

Options:
      --content-directory <path>
          Path to a directory containing content files.
          
          This directory is used to create the website.

  -q, --quiet
          Silence all output

      --index-route <route>
          What to serve when the request URI has an empty path.
          
          A request for http://mysite.com/ gets a response from this route. If this
          option is not set, such requests always receive a 404.

  -v, --verbose...
          Verbose mode; multiple -v options increase the verbosity

      --error-handler-route <route>
          What to serve when there are errors.
          
          This facilitates custom error pages. When there is an HTTP error this route
          is used to create the response. The HTTP status code can be obtained from
          the `error-code` render parameter.
          
          If the error handler itself fails then a default error message is used.

      --bind-to <socket-address>
          The TCP address/port that the server should bind to.
          
          This is an IP address and port number. For example, "127.0.0.1:80".

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version

Quick Start

Let's run this website:

Then open http://localhost:8080 in your browser of choice.

Try making a change to the site (in operator-website/content) and restart the server to see the update.

Content

When Operator starts up it crawls through your content directory to build a representation of your website. The site's routes and configuration are derived from this directory.

Operator needs to know what media type will be emitted by each content file. This is specified via file extensions (.html is text/html, .js is text/javascript, .png is image/png, and so on).

There are three different kinds of content files:

  1. Static files are served directly. For example, you can drop an image or html file into your content directory and it'll be served as is.

    Static files only have one extension (about.html, kittens.mp4, etc).

  2. Executables are run at request time, with standard output piped out as the response body. Any program that you can run from the command line will work (scripts, compiled programs, etc). The executable is invoked with no CLI arguments and with its working directory set to its own parent folder.

    An environment variable named OPERATOR_RENDER_DATA is provided to executables. Its value is render data encoded as JSON. This is the same data provided to handlebars templates.

    Executables have two extensions, with the first one indicating the media type of the executable's output (contact.html.py, styles.css.sh, dankmeme.jpg.exe, etc). Operator requires execute permissions on these files, and scripts will typically need a shebang so your OS knows how to interpret them.

    Operator doesn't care what the second extension is for executables, but you can use it to indicate the file type—for example, contact.html.py would be a Python script which outputs HTML. In executables the file type is usually not the same as its output type, although if you're feeling feisty then things like wat.js.js are certainly possible.

  3. Handlebars templates are compiled during server startup and rendered at request time. The heavy lifting is done by the handlebars Rust library which is largely compatible with the original JavaScript handlebars implementation. Operator provides some render data and a custom get helper to make your content composable.

    Like executables, handlebars templates also have two extensions. The first one indicates the media type, and the second one must be .hbs to tell Operator that it's a template (faq.html.hbs, metadata.json.hbs, etc).

Security

Operator is only as secure as your content directory, so be careful! Here are some best practices: