Net.HTTP
module Net.HTTP
Buffered HTTP clients, responses, and a small declaration-ordered server router. Requests never follow redirects or perform generic retries implicitly.
using Net.HTTP
let response = HTTP.get("https://example.test/").try
response.status.success? # => true
For connection reuse and statistics, own a client explicitly:
let client = Client.open.try
let response = client.get("https://example.test/").try
client.close.try
record Headers
An insertion-ordered HTTP field collection. Names compare case-insensitively and duplicate fields are preserved.
Fields
entries[(String, String)]
record Status
A validated HTTP status code in 100..599.
Fields
codeInteger
record Response<B>
A typed HTTP response envelope whose body representation is explicit.
Fields
statusStatusheadersHeadersbodyB
record Request<B>
A typed HTTP request envelope whose body representation is explicit.
Fields
methodStringtargetURIheadersHeadersbodyB
record RouteContext
Route captures decoded after path segmentation.
Fields
parametersMap<String, String>optional
record Context
Per-request server context.
Fields
routeRouteContext
type Handler
A buffered HTTP route handler.
Variants
- abstract
record Route
One declared route; routers preserve declaration order.
Fields
methodStringpathStringhandlerHandler
record Router
An immutable, declaration-ordered HTTP router.
Fields
routes[Route]optional
record ShutdownReport
Counts and elapsed time from graceful server shutdown.
Fields
completedIntegerfailedIntegerforcedIntegerelapsedMillisecondsInteger
record ServerOptions
Bounded HTTP server resources and default graceful-shutdown duration.
Fields
maximumHandlersIntegeroptionalbacklogIntegeroptionalgracefulShutdownDurationoptional
record PoolOptions
HTTP connection-pool bounds and idle lifetime.
Fields
perOriginIntegeroptionaltotalIntegeroptionalqueuedRequestsIntegeroptionalidleExpiryMillisecondsIntegeroptional
record ClientOptions
Options owned by an explicit HTTP client.
Fields
poolPoolOptionsoptional
record ClientStatistics
Lifetime request/reuse counters plus current pooled connections.
Fields
openConnectionsIntegerrequestsIntegerreusedConnectionsInteger
record ClientCloseReport
Resources released by Client.close.
Fields
closedConnectionsInteger
type Client
The pooled HTTP client. An opaque handle over the connection pool that owns it; Client.open makes one and client.close releases it.
module Net.HTTP.Headers
Construction and parsing of validated HTTP header collections.
constant empty Headers
Returns a field collection with no entries.
function from
Validates header names and values without folding duplicates.
Duplicate fields stay in their original order. Invalid names and values containing line breaks are rejected instead of creating a malformed or injectable HTTP message.
from(entries) : [(String, String)] -> Result<Headers, NetError>
Returns: Result<Headers, NetError> — validated fields, or Parse
Examples
Forwarding an explicitly selected set of request headers
Headers.from([
("Accept", "application/json"),
("X-Request-ID", requestId)
]).try
function parse
Parses CRLF- or LF-separated header fields.
Use this at a protocol boundary when headers arrive as text. Application code normally builds them with from, add, and set.
parse(text) : String -> Result<Headers, NetError>
Returns: Result<Headers, NetError> — fields in source order, or Parse
Examples
Parsing headers captured from a diagnostic fixture
Headers.parse("Content-Type: text/plain\r\nX-Trace: abc\r\n").try
module Net.HTTP.Status
Validation for numeric HTTP status codes.
function from
Validates an HTTP status code.
from(code) : Integer -> Result<Status, NetError>
Parameters
codeInteger- a status in
100..599
Returns: Result<Status, NetError> — the status, or Parse
Examples
Validating a configurable health-check success code
let code = ENV.get("HEALTH_STATUS").flatMap { |text| text.to(Integer) }.or(204)
let expected = Status.from(code).try
module Net.HTTP.Response
Buffered response constructors for route handlers.
function binary
Builds a buffered binary response with validated headers.
binary(status, body, headers)
Examples
Returning a downloaded file without decoding it as text
Response.binary(200, archive, Headers.empty.set("Content-Type", "application/zip"))
function text
Builds a UTF-8 text response with an explicit text/plain content type.
text(status, body)
Examples
A small health endpoint
Response.text(200, "ok")
function empty
Builds a response with an empty body.
empty(status)
Examples
A successful DELETE endpoint
Response.empty(204)
module Net.HTTP.Router
The empty starting point for an immutable route declaration chain.
constant build ?
make Router
route
Appends a route; earlier matching declarations win.
Use this for a method without a convenience function. Paths may include named or wildcard captures, which the handler reads from RouteContext.
route(method, path, handler)
Examples
Adding a custom method
router.route("PURGE", "/cache/:key", ~purge)
get
Appends a GET route. GET also supplies automatic HEAD fallback.
get(path, handler)
head
Appends an explicit HEAD route, overriding automatic GET fallback.
head(path, handler)
options
Appends an explicit OPTIONS route, overriding generated OPTIONS.
options(path, handler)
post
Appends a POST route.
post(path, handler)
put
Appends a PUT route.
put(path, handler)
patch
Appends a PATCH route.
patch(path, handler)
delete
Appends a DELETE route.
delete(path, handler)
module Net.HTTP.Server
Starting, observing, and gracefully stopping HTTP servers.
type Running
An opaque asynchronous HTTP server handle.
function start
Starts a server with conservative defaults and returns immediately.
The returned handle owns the listener and active handlers. Use start when the process has other work to do; use serve for a foreground server whose main job is handling HTTP.
start(endpoint, router)
Examples
let router = Router.build.get("/health", do |request, context|
Response.text(200, "ok")
end)
let endpoint = Net.Socket.TCP.Endpoint.loopback(Net.Port.from(0).try)
let server = Server.start(endpoint, router).try
Server.stop(server).try
function serve
Starts with defaults and blocks until the server stops.
serve(endpoint, router)
function stop
Gracefully stops using the duration captured at start.
New requests stop being accepted while in-flight handlers get their grace period to finish. The report says how much work completed or was forced down during shutdown.
stop(server)
Examples
Shutting down from an application lifecycle hook
let report = Server.stop(server).try
IO.printLine("closed after ${report.completed} requests")
function join
Waits until the server owner exits.
join(server)
function running?
running?(server)
Returns: Bool — whether the server owner is alive
function localAddress
Returns the bound address, including an operating-system-assigned port.
localAddress(server)
Returns: Net.Socket.TCP.Endpoint — the bound address
Examples
Publishing the actual address of a test server
let endpoint = Server.localAddress(server)
IO.printLine("test server: http://${endpoint.host}:${endpoint.port.string}")
module Net.HTTP.Client
Constructors for explicitly owned, connection-pooling HTTP clients.
function open
Opens an explicit pooled client with conservative defaults.
Reuse one client for related requests so keep-alive connections and DNS work can be reused. Close it when the owning service shuts down.
open() : Result<Client, NetError>
open(options) : ClientOptions -> Result<Client, NetError>
Examples
Fetching several pages through one connection pool
let client = Client.open.try
let first = client.get("https://api.example.com/items?page=1").try
let second = client.get("https://api.example.com/items?page=2").try
client.close.try
make Client
request
Sends a buffered request. Redirects and generic retries are not implicit.
This keeps policy with the caller: inspect a redirect before following it, and retry only methods and failures your application knows are safe.
request(method, url, headers, body)
Examples
Sending JSON with an idempotency key
let headers = Headers.empty
.set("Content-Type", "application/json")
.set("Idempotency-Key", requestId)
client.request("POST", url, headers, JSON.stringify(order).to(Binary).try)
get
Sends a buffered GET request.
get(url)
post
Sends a buffered binary POST request.
post(url, body)
put
Sends a buffered binary PUT request.
put(url, body)
patch
Sends a buffered binary PATCH request.
patch(url, body)
delete
Sends a DELETE request with an empty body.
delete(url)
head
Sends a HEAD request; the returned body is empty.
head(url)
options
Sends an OPTIONS request.
options(url)
statistics
Reports current pool occupancy and lifetime request counters.
statistics()
Returns: ClientStatistics — current pool and lifetime request counters
Examples
Emitting client-pool diagnostics
let stats = client.statistics
IO.printLine("HTTP reuse: ${stats.reusedConnections}/${stats.requests}")
close
Idempotently closes the client and every idle pooled connection.
Further requests fail with Closed; a second close is harmless.
close()
make Headers implements Showable, Inspectable
add
Appends a field without replacing existing fields of the same name.
add(name, value)
Examples
Headers.empty.add("Accept", "text/plain")
set
Replaces all fields of name with one value.
set(name, value)
Examples
headers.set("Content-Type", "application/json")
remove
Removes every field matching name case-insensitively.
remove(name)
Examples
Stripping hop-by-hop state before forwarding
let forwarded = incoming.remove("Connection")
get
Returns the first matching field value.
get(name)
Examples
Selecting a response decoder
let contentType = response.headers.get("Content-Type").or("application/octet-stream")
getAll
Returns every matching value in insertion order.
getAll(name)
Examples
Preserving every Set-Cookie field
let cookies = response.headers.getAll("Set-Cookie")
inspectValue
Structural inspection uses the same credential-safe rendering.
inspectValue(colors)
make Status
make RouteContext
parameter
Returns one decoded named or wildcard route capture.
parameter(name)
Parameters
nameString- the capture name declared in the route
Returns: Result<String, NetError> — the capture, or Parse when absent
Examples
Reading :id from a /users/:id route
let id = context.parameter("id").try
module Net.HTTP.HTTP
Stateless HTTP convenience calls for scripts and occasional requests.
function request
Sends one stateless buffered request with no redirect or hidden retry.
Each call owns a short-lived client. This is convenient for scripts and occasional requests; use Client for a service making repeated calls.
request : String -> String -> Headers -> Binary -> Result<Response<Binary>, NetError>
Examples
A one-off authenticated request in a command-line tool
let headers = Headers.empty.set("Authorization", "Bearer ${token}")
HTTP.request("GET", url, headers).try
function get
Sends one stateless buffered GET.
get(url) : String -> Result<Response<Binary>, NetError>
Examples
HTTP.get("https://example.test/").try
function delete
Sends one stateless DELETE with an empty body.
delete(url) : String -> Result<Response<Binary>, NetError>
function head
Sends one stateless HEAD and returns an empty response body.
head(url) : String -> Result<Response<Binary>, NetError>
function options
Sends one stateless OPTIONS request.
options(url) : String -> Result<Response<Binary>, NetError>
function post
Sends one stateless buffered binary POST.
post(url, body) : String -> Binary -> Result<Response<Binary>, NetError>
function put
Sends one stateless buffered binary PUT.
put(url, body) : String -> Binary -> Result<Response<Binary>, NetError>
function patch
Sends one stateless buffered binary PATCH.
patch(url, body) : String -> Binary -> Result<Response<Binary>, NetError>
Submodules
Net.HTTP.WebSocketHigh-level RFC 6455 client messages. The runtime handles fragmentation and ping/pong frames; reconnect and heartbeat policies remain application-owned.