The App

Static files and error pages

A Rails app serves public/404.html, public/500.html and robots.txt even in --api mode, because that happens below the router, not in a view. Bogie does the same with a public/ folder that is go:embedded into the binary, so a deployed container needs no files beside it. Since v0.2.7; index.html at / since v0.2.8.

What a new app has

public/
  public.go            //go:embed *.html images
  404.html             any request nothing answered
  500.html             a handler that panicked
  images/              the mascot art the two pages use

How a request reaches public/

Every real route wins first. A request no route matched goes through three handlers, mounted in app/controllers/routes.go:

r.NoRoute(s.staticFile, s.welcome, s.notFound)
  1. staticFile looks the request path up in public/ and, if a file is there, serves it as itself, with its content type from the extension. / means public/index.html.
  2. welcome answers GET / in development only, when nothing above did.
  3. notFound answers with public/404.html and status 404, always.

A panicking handler gets public/500.html from middlewares.Recover, outside this chain. Edit either page freely; they are yours.

Adding a file

Drop it in public/, then widen the go:embed line in public/public.go so the binary carries it. Only what the pattern matches is embedded; anything else is a 404 even though it is on disk.

// public/public.go
//go:embed *.html *.txt *.ico css images
var Files embed.FS

With that line, public/robots.txt answers at /robots.txt, public/favicon.ico at /favicon.ico, and public/css/app.css at /css/app.css, in every environment. A directory named in the pattern brings everything under it.

A page at /

Add public/index.html (already matched by *.html) and GET / serves it in every environment, ahead of the development welcome page. A controller mounted at / still wins over both.

What it is not

  • Not an asset pipeline. Files are served as they are: no compiling, no fingerprinted names.
  • Not for uploads. public/ is fixed when the binary is built. Files users upload at runtime need storage of their own and a controller that serves them.
  • Not a CDN. Embedded files carry no modification time, so no Last-Modified header is sent; put a cache or CDN in front if the files are large or hot.

Product images and other uploads. Because public/ is fixed when the app is built, an image a user uploads, such as a product photo in a shop, cannot land there: it needs storage of its own, outside the binary. Uploads are out of the book's scope; public/ is for the files you ship with the app.

Bringing it to an older app

Commit your work, then bogie app:update: it adds public/ and app/controllers/public.go, and merges the updated routes.go, welcome.go and middlewares. See Upgrading an app.