8.6.4. HV-04 — Advanced HTTP Server Features

This tutorial covers advanced server capabilities — static file serving, CORS, HTTP redirects, binary responses, custom headers and caching, content-type control, and status codes.

Prerequisites: HV-03 — HTTP Server Basics (basic routes and JSON).

8.6.4.1. Static File Serving

STATIC maps a URL prefix to a filesystem directory. All files under that directory are served with the correct Content-Type based on their extension.

Two spellings reach the same call. From outside the class, the free function takes the native server handle — the server field of your HvWebServer instance:

// After server->init(port) but before server->start():
STATIC(server.server, "/static", "/path/to/public")

Inside onInit the class method takes the path and directory alone: STATIC("/static", "/path/to/public").

Important

STATIC must be called after init() (which registers the HTTP service with the router) and before start(). onInit itself runs inside init(), so registering there is in time.

Clients can then fetch /static/index.html, /static/style.css, etc.

8.6.4.2. CORS (Cross-Origin Resource Sharing)

allow_cors() enables CORS headers on all responses. Call it in onInit, alongside your route registrations:

class AdvancedServer : HvWebServer {
    def override onInit {
        allow_cors()
        // ... routes ...
    }
}

The server will respond to OPTIONS preflight requests automatically with Access-Control-Allow-Origin and related headers.

Every route snippet below is a body of AdvancedServer’s onInit — each one goes where the // ... routes ... comment sits.

8.6.4.3. HTTP Redirects

REDIRECT(resp, location, status) sends a redirect response:

GET("/old-path") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    return resp |> REDIRECT("/new-path", http_status.MOVED_PERMANENTLY)
}

Common redirect status codes:

  • http_status.MOVED_PERMANENTLY (301) — permanent redirect, browsers cache it

  • http_status.FOUND (302) — temporary redirect

8.6.4.4. Custom Response Headers and Caching

Use set_header on the response to add cache-control, ETags, and custom application headers:

GET("/cached") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    set_header(resp, "Cache-Control", "max-age=3600, public")
    set_header(resp, "ETag", "\"v1.0\"")
    set_header(resp, "X-Server", "daslang")
    return resp |> TEXT_PLAIN("cached response")
}

8.6.4.5. Binary Response

DATA(resp, data, length) sends raw bytes with Content-Type: application/octet-stream:

GET("/binary") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    let payload = "BINARY\x00DATA1234"
    return resp |> DATA(payload, 16)
}

8.6.4.6. Content-Type and Status Codes

set_content_type(resp, type) gives full control over the response:

// HTML response
GET("/html") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    set_content_type(resp, "text/html")
    resp.body := "<h1>Hello from daslang!</h1>"
    return http_status.OK
}

8.6.4.6.1. Non-200 JSON Responses

JSON() and TEXT_PLAIN() accept an optional status parameter (defaults to http_status.OK):

GET("/not-found") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    let payload = (error = "resource not found", code = 404)
    return resp |> JSON(write_json(JV(payload)), http_status.NOT_FOUND)
}

8.6.4.6.2. 201 Created with Location Header

POST("/items") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    set_header(resp, "Location", "/items/42")
    let payload = (id = 42, body = string(req.body))
    return resp |> JSON(write_json(JV(payload)), http_status.CREATED)
}

8.6.4.6.3. 204 No Content

POST("/ack") <| @(var req : HttpRequest?; var resp : HttpResponse?) : http_status {
    return http_status.NO_CONTENT
}

8.6.4.7. Quick Reference

Function

Description

STATIC(path, dir)

Serve static files from directory (method)

STATIC(server.server, path, dir)

Same, from outside the server class

allow_cors()

Enable CORS headers on all routes

REDIRECT(resp, location, status)

Send 3xx redirect response

JSON(resp, json_str, status?)

JSON response (default 200)

TEXT_PLAIN(resp, text, status?)

text response (default 200)

DATA(resp, data, length, status?)

Binary response (default 200)

set_header(resp, key, value)

Set response header

set_content_type(resp, type)

Set Content-Type header