Overview

Clace supports deploying any type of app, in any language/framework, using containerized apps. Apps can also be built where the backend API is in the container but the UI is built using Clace. Clace UI applications implement a Hypermedia driven approach for developing web applications. Applications return HTML fragments as API response using Go html templates. The UI uses HTML enhanced with hypermedia controls using the HTMX library to implement user interactions.

The backend API routes and dependencies like CSS library, JavaScript modules etc are configured using Starlark configuration. Any custom API handling required is implemented in handler functions also written in Starlark. Starlark is a subset of python, optimized for application configuration use-cases.

App Types

Clace apps can be of few different types:

  • Action apps: Actions allow apps to expose an autogenerated UI for simple backend actions.
  • Containerized apps: The whole app is implemented in a container, Clace proxies the container results. This uses the container and proxy plugins. No Starlark code is required for this.
  • Starlark apps: These use the Clace plugins to implement the whole app. No containers are required for such apps.
  • Hybrid apps: The backend APIs are implemented in a container. Clace is used to implement the Hypermedia based UI using Starlark handlers. This uses the http plugin to talk to the backend API and the container plugin to configure the backend.

This section of the docs covers Starlark and Hybrid apps. For a containerized app, the --spec definition includes all the app definition. There is no need to do any custom Starlark config for a regular containerized app.

Sample Starlark App

To create an app with a custom HTML page which shows a listing of files in your root directory, create an ~/myapp4/app.star file with

app.star
load("exec.in", "exec")

def handler(req):
   ret = exec.run("ls", ["-l", "/"])
   if ret.error:
       return {"Error": ret.error, "Lines": []}
   return {"Error": "", "Lines": ret.value}

app = ace.app("hello4",
              custom_layout=True,
              routes = [ace.html("/")],
              permissions = [ace.permission("exec.in", "run", ["ls"])]
             )

and an ~/myapp4/index.go.html file with

index.go.html
<!doctype html>
<html>
  <head>
    <title>File List</title>
    {{ template "clace_gen_import" . }}
  </head>
  <body>
    {{ .Data.Error }}
    {{ range .Data.Lines }}
       {{.}}
       <br/>
    {{end}}
  </body>
</html>

Run clace app create --auth=none --dev --approve ~/myapp4 /hello4. After that, the app is available at /hello4. Note that the --dev option is required for the clace_gen_import file to be generated which is required for live reload.

This app uses the exec plugin to run the ls command. The output of the command is shown when the app is accessed. To allow the app to run the plugin command, use the clace app approve command.

⚠️
Note: If running on Windows, change ls to dir. Else, use the fs plugin to make this platform independent. See https://github.com/claceio/apps/blob/main/system/disk_usage/app.star.

Custom Layout HTML App

To return HTML response, a HTML template file named *.go.html is required. Create an ~/myapp2/app.star file containing

app.star
app = ace.app("hello2",
        custom_layout=True,
        routes = [ace.html("/")]
)

and an ~/myapp2/index.go.html file containing

index.go.html
hello world2

Run clace app create --auth=none ~/myapp2 /hello2. After that, the app is available at /hello2

$ curl localhost:25222/hello2
hello world2

The ~/myapp2/index.go.html can be updated to have a complete HTML page. Use the command clace app reload --promote /hello2 to pick up changes. This app is using custom_layout=True which means the app developer has to provide the complete HTML.

Default Layout HTML App

The default is custom_layout=False meaning app developer has to provide only the HTML body, Clace will automatically generate the rest of the HTML. For using the auto generated HTML templates, the app has to be created in dev mode using the --dev option.

Create an ~/myapp3/app.star file containing

app.star
app = ace.app("hello3",
        routes = [ace.html("/")]
)

and an ~/myapp3/app.go.html file containing

app.go.html
{{block "clace_body" .}}
   hello world3
{{end}}

Run clace app create --auth=none --dev ~/myapp3 /hello3 . After that, the app is available at /hello3. Note that the --dev option is required for the index_gen.go.html file to be generated.

There is only one route defined, for page /, which shows a HTML page with the name of the app. The body is generated from the contents of the app.go.html file. A more verbose way to write the same app config would be

app.star
app = ace.app(name="hello3",
              custom_layout=False,
              routes = [ace.html(path="/", full="index_gen.go.html")]
             )

Automatic Error Handling

To enable automatic error handling (recommended), add an error_handler function like:

app.star
def error_handler(req, ret):
    if req.IsPartial:
        return ace.response(ret, "error", retarget="#error_div", reswap="innerHTML")
    else:
        return ace.response(ret, "error.go.html")