NURLNURL registrynurl-lang.org →

← all packages

http

owner @Hindurable

Install

[dependencies]
http = "^0.3.1"

Versions

Dependencies (latest)

None.

http — the unified HTTP server interface for NURL

One dependency for anything that needs to serve HTTP. NURL's stdlib already ships a complete HTTP stack — sockets + TLS, a request parser, a response builder, a keep-alive server with worker pools and DoS limits, a router, static-file serving, and auth / jwt / multipart / middleware / websocket helpers. What it doesn't ship is the ~40 lines of glue every server re-invents: bind → build a router → install a shutdown signal → wrap the handler in logging / CORS / panic-recovery → run the keep-alive loop.

http is that glue, as an ergonomic, dependency-importable facade — plus the whole stdlib surface pulled in transitively, so you $-include one file and have everything a handler needs in scope.

Hello, server

$ `deps/http/src/http.nu`

@ main → i {
    : *HttpApp a ( http_app_new )
    ( http_app_get a `/` \ HttpRequest req Params p → HttpResponse {
        ^ ( response_text 200 `hello` )
    } )
    ( http_app_get a `/hi/:name` \ HttpRequest req Params p → HttpResponse {
        : String o ( string_from `hi ` )
        ?? ( params_get p `name` ) { T n → { ( string_push_str o ( string_data n ) ) ( string_free n ) } F j → { ( string_free j ) } }
        : HttpResponse r ( response_text 200 ( string_data o ) )
        ( string_free o )
        ^ r
    } )
    ^ ( http_app_listen a `127.0.0.1` 8080 )   // blocks; returns an exit code
}

The App API

Construction & serving:

CallEffect
( http_app_new )*HttpAppcreate an app (free with http_app_free)
( http_app_listen a host port )ibind + serve until closed (SIGINT/SIGTERM/error)
( http_app_listen_tls a host port cert key )isame, over TLS (PEM paths; EC or RSA leaf)

Routing (handlers are ( @ HttpResponse HttpRequest Params )):

Call
( http_app_get a pattern h )also http_app_post / put / patch / delete
( http_app_route a method pattern h )any method
( http_app_use_router a router )adopt a pre-built Router (keeps it socket-testable)
( http_app_router a )Routerthe embedded router

Patterns use the stdlib router: :name captures a segment (read with params_get), *rest is a tail wildcard.

Configuration (call before serving):

CallDefault
( http_app_static_dir a dir )offserve files for unmatched GET/HEAD (traversal-safe)
( http_app_cors a )offpermissive CORS + 204 OPTIONS preflight
( http_app_logging a )offaccess log (method path → status) to stderr
( http_app_recover a on )onhandler panic → 500 instead of a dropped connection
( http_app_workers a n )00 = single-threaded keep-alive; n > 0 = worker pool
( http_app_idle_ms a ms )5000keep-alive idle timeout
( http_app_body_max a bytes )10 MiBrequest-body cap (parser answers 413 above it) — raise for upload endpoints
( http_app_head_max a bytes )8 KiBrequest-head cap
( http_app_max_keepalive a n )1000per-connection request reuse cap (0 = close after one)
( http_app_request_timeout a ms )offper-request wall-clock budget → stock 504 on overrun
( http_app_quiet a )offsuppress the startup banner

Everything under the facade is the untouched stdlib implementation, in scope from the one include: HttpRequest / HttpResponse, response_text / response_json / response_new / response_set_header / …, Router / params_get, plus the auth, jwt, multipart and websocket helpers.

Wrapping an existing router

A server that already builds a Router (e.g. to keep every route testable without a socket) drops onto the facade with one seam:

@ my_service_router → Router { ... router_post r `/x` h ... ^ r }

@ my_serve s host i port → i {
    : *HttpApp a ( http_app_new )
    ( http_app_use_router a ( my_service_router ) )   // adopt the routes
    : i rc ( http_app_listen a host port )            // facade owns the glue
    ( http_app_free a )
    ^ rc
}

The anomaly package's HTTP service is served exactly this way.

Memory model

http_app_new returns a heap *HttpApp, mutable across the registration calls; free it with http_app_free. The embedded Router holds a stable Vec handle, so registrations accumulate correctly. http_app_listen moves the bound listener into the server and stops it on return.

Tests

./tests/http_test.sh builds tests/smoke.nu (a server exercising routing, path params, POST bodies, static fallback, CORS, and panic recovery) and drives it over curl — including that the keep-alive loop survives a handler panic.