Response
Response Data
The response from the handler function is passed to the template to be converted to HTML. The handler response is accessible through .Data, or $.Data from a nested template scope such as range or with. Any supported Starlark value can be used as the return value. Using a dictionary is recommended, so that error handling is easier. Adding an Error key in the response dict can indicate to the template that an error condition needs to be handled.
For example, a handler like
def handler(req):
name = req.Query.get("name")
if name:
return {"Name": name[0], "Error": None}
else:
return {"Error": "Name not specified", "Name": None}
app = ace.app("test", routes = [ace.html("/")])allows the template to handle the error by doing
{{block "openrun_body" .}}
{{if .Data.Error}}
<div style="color: red">{{.Data.Error}}</div>
{{else}}
Hi {{.Data.Name}}
{{end}}
{{end}}Redirect Response
If the API needs to redirect the client to another location after a POST/PUT/DELETE operation, the handler function can return an ace.redirect structure. The fields in this structure are:
| Property | Optional | Type | Default | Notes |
|---|---|---|---|---|
| url | false | string | The url to redirect to | |
| code | true | int | 303 | The HTTP status code, 303 or 302 |
For example, this code does a 303 redirect after a POST API, which provides handling for update requests.
def create_game(req):
level = req.Form["level"]
ret = http.post(SERVICE_URL + "/api/create_game/" + level[0])
return ace.redirect(req.AppPath + "/game/" + ret.value.json()["GameId"])Custom Response
In some cases, a custom response needs to be generated, with special headers. Or the response needs to use a template different from the one defined in the route, which could happen in the case of an error. For such cases, an ace.response structure can be returned by the handler. The fields in this structure are:
| Property | Optional | Type | Default | Notes |
|---|---|---|---|---|
| data | false | object | The response data | |
| block | true | string | Template block override; otherwise uses the route block | |
| type | true | string | inherited from the route type definition | If “json”, block is ignored |
| code | true | int | 200 | HTTP status code |
| retarget | true | string | HX-Retarget header value, CSS selector to target, like “#error_id” | |
| reswap | true | string | HX-Reswap, like “outerHTML” | |
| redirect | true | string | Set HX-Redirect on an HTML response. | |
| download | true | string | Attachment filename; see File Downloads below. | |
| content_type | true | string | application/octet-stream for downloads | Download MIME type. |
For example, this handler code uses retarget to handle errors by updating the html property which has id “gameErrorId”
ret = http.post(api_url).value.json()
if ret.get("Error"):
return ace.response(ret, "game_error_block", retarget="#gameErrorId")
return fetch_game(req, game_id)This code returns a 404 with a custom body generated from a template block called “invalid_challenge_block”
if challenge.get("Error"):
return ace.response(challenge, "invalid_challenge_block", code=404)htmx 4 swaps error responses (4xx and 5xx) into the target like any other response, so the block above is shown in place of the target; htmx 2 did not swap them. To keep an error response out of the page, or to route it elsewhere, use the hx-status attribute on the requesting element, like hx-status:404="swap:none" or hx-status:4xx="target:#errors", or set htmx.config.noSwap for the whole app.
File Downloads
Return ace.response with download set to a filename to send an attachment. Set content_type to its MIME type; the default is application/octet-stream. Download data can be a string, bytes, or a download stream returned by a plugin.
def download_report(req):
return ace.response(
"name,count\nbookmarks,12\n",
download="report.csv",
content_type="text/csv",
)
app = ace.app("Reports", routes=[ace.api("/report", handler=download_report)])Downloads bypass template and JSON rendering.
JSON Response
HTML routes return HTML by default; ace.api routes return JSON by default. There are some cases where data needs to be returned to the client in JSON format. The type property can be used for those cases. For example, this API returns JSON
ace.api("/memory", handler=memory_handler),Here, the response from the handler function is returned as JSON, no template is used. Also, in this handler, if there is a call to ace.response, the type will default to JSON since that is the type specified at the route level. Mime type detection based on the Accept header is planned, it is not currently supported.
Skip to content