I have published a prototype Starlark view plugin for Caddy. The plugin is an alternative to Caddy’s built-in Go templates. It lets you write Flask-style view functions in Starlark that take a request and return a response. Starlark is a restricted Python-like configuration and scripting language. The plugin is mostly AI-generated code. I have reviewed and revised the code to a degree and have tested it locally, but I haven’t deployed it.
This plugin stems from frustration with Go templates in Caddy. Go templates are not designed to express complex logic, but when you use Caddy’s template handler, the logic has no place to go except the template itself and vars with CEL expressions. The template syntax is Lispy enough to be confusing when the language isn’t actually a Lisp.
Note I am not convinced Starlark with a Flask-like API is the right approach. As a replacement for Go templates, it is only one option alongside others like gonja (a template language based on Jinja). I’ve also had my share of frustrations with Jinja. I want to see whether Starlark code is more maintainable and makes the departure from conventional templates worth it.
Here is an example of a view. It is a rewrite of my error page template.
def respond(request):
code = int(placeholder("http.error.status_code"))
text = placeholder("http.error.status_text")
message = placeholder("http.error.message")
if message.strip() != "":
if not message.endswith("."):
message += "."
elif code == 403:
message = "You don't have permission to access this resource."
elif code == 404:
message = "The requested URL was not found on this server."
elif code == 500:
message = "An internal server error has occurred."
else:
message = text + "."
# `html()` is like `str.format()` but escapes raw strings and returns `Markup`.
# It passes through `Markup` already escaped with `html()`.
return html(
"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{code} {text}</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
</head>
<body>
<h1>Error {code}</h1>
<p>{message}</p>
<ul>
<li><a href="/">Home</a></li>
<li><a href="#" onclick="javascript:history.back(); return false;">Back</a></li>
<li><a href="{url}" onclick="javascript:window.location.reload(); return false;">Reload</a></li>
</ul>
</body>
</html>
""",
code=code,
text=text,
message=message,
url=request.url,
), code