Overview
OpenRun 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 OpenRun. OpenRun 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
OpenRun 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, OpenRun proxies the container results. This uses the container and proxy plugins. No Starlark code is required for this.
- Starlark apps: These use the OpenRun plugins to implement the whole app. No containers are required for such apps.
- Hybrid apps: The backend APIs are implemented in a container. OpenRun 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
load("exec.in", "exec")
def handler(req):
ret = exec.run("ls", ["-l", "/"]).value
return {"Error": "", "Lines": ret}
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
<!doctype html>
<html>
<head>
<title>File List</title>
{{ template "openrun_gen_import" . }}
</head>
<body>
{{ .Data.Error }}
{{ range .Data.Lines }}
{{.}}
<br/>
{{end}}
</body>
</html>
Run openrun 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 openrun_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 openrun app approve
command.
ls
to dir
. Else, use the fs
plugin to make this platform independent. See https://github.com/openrundev/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 = ace.app("hello2",
custom_layout=True,
routes = [ace.html("/")]
)
and an ~/myapp2/index.go.html
file containing
hello world2
Run openrun 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 openrun 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, OpenRun 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 = ace.app("hello3",
routes = [ace.html("/")]
)
and an ~/myapp3/app.go.html
file containing
{{block "openrun_body" .}}
hello world3
{{end}}
Run openrun 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 = 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:
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")