Files
Flash5/docs/lifecycle/response/RESPONSE.md
T

4.0 KiB

Response

The Response object is the mutable view of an outgoing HTTP/1.1 response. It is pre-initialised by the server (200 / text/plain) and passed to every handler as res. All mutating methods return this for fluent chaining.

server.get("/hello", (req, res) -> res.body("hello"));
server.post("/items", (req, res) -> res.status(HttpStatus.CREATED).body("created"));

Status code

res.status(404)                   // int overload — phrase looked up via HttpStatus.bytesForCode()
res.status(HttpStatus.NOT_FOUND)  // enum overload — pre-encoded bytes written directly, zero lookup

Prefer the HttpStatus overload on hot paths: the pre-encoded byte[] is written to the socket without any lookup. The int overload falls back to an O(1) array lookup — still zero allocation, just one extra indirection.


Content type

res.type(ContentType.JSON)           // enum — pre-encoded bytes, zero allocation
res.type("application/octet-stream") // String — encoded once at call time

Same pattern as status: the ContentType enum carries pre-encoded bytes; the String overload encodes once and stores the result.


Body modes

Three mutually exclusive modes. The last one set wins.

Fixed body

res.body("hello")           // String → UTF-8 bytes
res.body(new byte[]{...})   // raw bytes

Written with Content-Length. The byte array is stored as-is; no copy on the write path.

Known-length stream

res.stream(Files.newInputStream(path), Files.size(path))

Written with Content-Length. The stream is drained directly to the socket in the write path — zero intermediate buffer beyond the OS socket buffer.

Unknown-length stream (chunked)

res.chunked(source)

Written with Transfer-Encoding: chunked. The server reads 8 KB at a time from source, writes each chunk with its hex-encoded length, and closes with the terminal 0\r\n\r\n. No Content-Length header is emitted.

Use when the body length is not known upfront: generated content, pipe-fed streams, proxied responses.


Custom headers

res.header("X-Request-Id", "abc123")
   .header("Cache-Control", "no-store")

Each header is encoded as "Name: Value\r\n" bytes at call time and stored in a list. On the write path the pre-encoded arrays are written directly — zero allocation per request.


Fluent chaining

All mutating methods return this. A complete response in one expression:

return res.status(HttpStatus.CREATED)
          .type(ContentType.JSON)
          .header("X-Trace-Id", traceId)
          .body(json);

Body mode decision guide

Payload Mode Header emitted
Small / fully known body() Content-Length
File or stream with known size stream(is, length) Content-Length
Generated / piped / unknown size chunked(is) Transfer-Encoding: chunked

Memory model

Call Allocation
status(HttpStatus) none — writes pre-encoded byte[] from enum
status(int) none — O(1) array lookup at write time
type(ContentType) none — pre-encoded byte[] from enum
type(String) encodes once at call time, stored as byte[]
body(String) one UTF-8 encode at call time
body(byte[]) none — array stored by reference
stream(is, len) none — stream drained directly to socket
chunked(is) 8 KB read buffer per write call (stack-local)
header(name, value) one UTF-8 encode at call time per header