Production-ready HTTP client, server, router, compression, and middleware toolkit for the Alya language ecosystem.
- ⚡ High Performance & Reactive I/O: Fast protocol parsing and routing. Seamlessly binds to
event::EventLoopfor non-blocking reactive concurrency (reactive_server), handling thousands of concurrent connections with zero thread overhead. - 🔌 RFC 6455 WebSockets: Full-duplex WebSocket server and client connections. Automatic handshake negotiation (
101 Switching Protocols), RFC test-vector verified framing (text, binary, ping, pong, close), and callback-driven protocol drivers (ws_on_message,ws_send, etc.). - 🗜️ Web Compression Toolkit: Native integration with
compresssupporting Brotli (br), Zstandard (zstd), Gzip (gzip), and Deflate (deflate). AutomaticAccept-Encodingnegotiation, server response compression middleware, pre-compressed static asset serving (.brand.gz), and client decompression. - 🌐 Full HTTP Client: Supports GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS with custom headers, query params, timeout handling, and automatic redirect following.
- 🔒 Native HTTPS: Real TLS 1.2 via
alya-lang/tls(RSA key exchange, certificate verification, binary-safe bodies) — no subprocess, no shell, no temp files. Verified live against OpenSSL and Python TLS servers. - 🚀 HTTP Server & Context: Built on low-level TCP sockets (
std/net) or non-blocking event loops, offering intuitive request context (HttpContext), JSON responses, text responses, file serving, and status helpers. - 🛣️ Parametric Router & Route Groups: Fast URL pattern matching with wildcard (
*path) and named parameters (:id), plus subrouter groups with shared path prefixes and middleware chains. - 🛡️ Extensible Middleware: Out-of-the-box middleware for Compression (
mw_apply_compression), CORS (cors_middleware), request logging (logger_middleware), panic recovery (recovery_middleware), and static file serving (static_middleware). - 🍪 Cookie & Header Management: RFC-compliant Cookie serialization/parsing (
Set-CookieandCookieheaders) and case-insensitive HTTP header operations.
http/
├── alya.toml # Package manifest
├── src/
│ ├── lib.alya # Public API facade & high-level constructors
│ ├── types.alya # Core struct definitions (HttpRequest, HttpResponse, Route, etc.)
│ ├── core/
│ │ ├── status.alya # HTTP status codes & standard status messages
│ │ ├── headers.alya # Case-insensitive header dictionary helpers
│ │ ├── cookies.alya # Cookie parsing, serialization, and Set-Cookie generation
│ │ ├── compression.alya# HTTP content encoding, negotiation, and compression engine
│ │ └── protocol.alya # HTTP/1.1 request & response parsing and serialization
│ ├── router/
│ │ ├── route.alya # Route definition and parameter extractor
│ │ ├── router.alya # HTTP router and route registry
│ │ └── group.alya # Route grouping with prefix and sub-middlewares
│ ├── server/
│ │ ├── context.alya # HttpContext request/response lifecycle helpers
│ │ ├── server.alya # TCP socket server, request loop, and connection handler
│ │ └── reactive.alya # Event-loop driven non-blocking reactive HTTP server adapter
│ ├── websocket/
│ │ ├── handshake.alya # RFC 6455 WebSocket upgrade & SHA-1 handshake accept token
│ │ ├── frame.alya # RFC 6455 frame serializer, deserializer, and masking
│ │ └── connection.alya # High-level WebSocket bidirectional connection driver
│ ├── client/
│ │ ├── client.alya # HttpClient implementation with socket IO and redirect loop
│ │ ├── tls_client.alya # Native HTTPS via alya-lang/tls (no curl bridge)
│ │ └── methods.alya # Convenience functions (http_get, http_post, etc.)
│ └── middleware/
│ ├── compress.alya # HTTP response compression middleware (Brotli, Zstd, Gzip, Deflate)
│ ├── cors.alya # Cross-Origin Resource Sharing (CORS) handler
│ ├── logger.alya # Request/response logging middleware
│ ├── recovery.alya # Crash and exception recovery middleware
│ └── static.alya # Static file serving with MIME detection & pre-compressed assets
├── examples/
│ ├── compression_demo.alya # Dedicated HTTP compression showcase
│ └── demo.alya # Comprehensive usage demo
├── tests/ # 15 comprehensive test suites (100% passing)
│ ├── test_client.alya
│ ├── test_compression.alya
│ ├── test_context.alya
│ ├── test_cookies.alya
│ ├── test_headers.alya
│ ├── test_https.alya
│ ├── test_middleware.alya
│ ├── test_protocol.alya
│ ├── test_reactive_server.alya
│ ├── test_router.alya
│ ├── test_server.alya
│ ├── test_status.alya
│ ├── test_websocket_conn.alya
│ ├── test_websocket_frame.alya
│ └── test_websocket_handshake.alya
└── benches/
└── bench_basic.alya # Performance micro-benchmarks
Add http to your project's alya.toml:
[dependencies]
http = { git = "https://github.com/alya-lang/http", branch = "main" }Or install it directly via the alya CLI:
alya add http --git https://github.com/alya-lang/http --branch main
alya install| Feature | Default | Description |
|---|---|---|
compress |
✅ | Response compression middleware (compression(), compress()/decompress(), server_enable_compression). Needs Lib/compress. |
event |
✅ | Event-driven reactive server (reactive_server). Needs Lib/event. |
mime |
✅ | Static file serving (serve_static, mw_serve_static). Needs Lib/mime. |
crypto, url, and tls stay required: WebSocket handshakes need SHA-1, clients need URL parsing, and TLS paths are woven through the server/client cores.
# Full build (default)
alya install
alya test
# Slim build (core client/server/router/middleware without the above)
alya install --no-default-features
alya test --no-default-featuresimport "http" as http
function main()
let app = http::router()
# Route with path parameter
app.get("/users/:id", "get_user")
# JSON API response route
app.post("/api/echo", "post_echo")
# Start listening on port 8080 with compression enabled
let srv = http::server(8080, "127.0.0.1", app)
http::server_enable_compression(srv, 256)
say "Server running on http://127.0.0.1:8080"
end
main()
import "http" as http
function main()
let srv = http::server(8080)
# Enable automatic response compression (Brotli > Zstandard > Gzip > Deflate)
# Responses >= 256 bytes will be compressed according to client's Accept-Encoding
http::server_enable_compression(srv, 256)
# Serve static directory with automatic .br / .gz pre-compressed asset detection
http::server_enable_static(srv, "/static", "./public")
end
main()
import "http" as http
function main()
# Simple GET request
let res = http::http_get("http://httpbin.org/get")
say "Status: " + str(res.status_code)
say "Body: " + res.body
# Client instance with custom options
let client = http::client(5000, 1, 3) # 5s timeout, follow redirects
let post_res = client.post("http://httpbin.org/post", "{\"hello\":\"world\"}", "application/json")
say "Response: " + post_res.body
end
main()
import "http" as http
function main()
# Create and serialize a secure cookie
let c = http::cookie("session_id", "xyz123", "/", 3600, 1, 1, "Strict")
let cookie_hdr = http::cookie_format(c)
say "Set-Cookie: " + cookie_hdr
# Parse cookies from incoming request header
let parsed = http::cookie_parse_all("theme=dark; session_id=xyz123")
say "Theme: " + parsed["theme"]
end
main()
| Function | Parameters | Description |
|---|---|---|
http_get(url, headers) |
url: string, headers: map |
Performs an HTTP GET request |
http_post(url, body, content_type, headers) |
url: string, body: string, ... |
Performs an HTTP POST request |
http_put(url, body, content_type, headers) |
url: string, body: string, ... |
Performs an HTTP PUT request |
http_patch(url, body, content_type, headers) |
url: string, body: string, ... |
Performs an HTTP PATCH request |
http_delete(url, headers) |
url: string, headers: map |
Performs an HTTP DELETE request |
http_query(url, body, content_type, headers) |
url: string, body: string, ... |
Performs an HTTP QUERY request (IETF safe method with body) |
client_new(timeout_ms, follow_redirects, max_redirects) |
timeout_ms: int, ... |
Instantiates a configured HttpClient |
| Function | Parameters | Description |
|---|---|---|
server_new(port, host, router) |
port: int, host: string, router: HttpRouter |
Creates a new HttpServer instance |
server_enable_compression(server, min_length) |
server: HttpServer, min_length: int |
Enables response compression middleware |
server_enable_static(server, prefix, dir) |
server: HttpServer, prefix: string, dir: string |
Enables static file serving with .br/.gz pre-compressed support |
server_enable_cors(server, origin, methods, headers) |
server: HttpServer, ... |
Enables CORS middleware |
server_enable_logger(server, enabled) |
server: HttpServer, enabled: int |
Enables request logger middleware |
context_json(ctx, status_code, json_str) |
ctx: HttpContext, status: int, json: string |
Sends a JSON response with proper header |
context_text(ctx, status_code, text_str) |
ctx: HttpContext, status: int, text: string |
Sends a plain text response |
| Function | Parameters | Description |
|---|---|---|
http_compress(data, encoding) |
data: string, encoding: string |
Compresses string with gzip, br, deflate, zstd |
http_decompress(bytes, encoding) |
bytes: list, encoding: string |
Decompresses byte array back into UTF-8 string |
http_negotiate_encoding(accept_header) |
accept_header: string |
Negotiates best algorithm (br > zstd > gzip > deflate) |
http_is_encoding_supported(encoding) |
encoding: string |
Returns 1 if encoding is supported, 0 otherwise |
compression(min_length) |
min_length: int |
Creates a new CompressionConfig struct (default 256 bytes) |
| Method | Parameters | Description |
|---|---|---|
router_new(not_found_action) |
not_found: string |
Instantiates a new route registry |
router_get(r, pattern, handler) |
pattern: string, handler: string |
Registers a GET route handler |
router_post(r, pattern, handler) |
pattern: string, handler: string |
Registers a POST route handler |
router_put(r, pattern, handler) |
pattern: string, handler: string |
Registers a PUT route handler |
router_delete(r, pattern, handler) |
pattern: string, handler: string |
Registers a DELETE route handler |
router_patch(r, pattern, handler) |
pattern: string, handler: string |
Registers a PATCH route handler |
router_query(r, pattern, handler) |
pattern: string, handler: string |
Registers a QUERY route handler |
router_group_add(r, prefix, ...) |
prefix: string, ... |
Registers a route under a group prefix |
| Function | Parameters | Description |
|---|---|---|
reactive_server(loop, port, host, router, on_req, on_ws) |
loop: EventLoop, ... |
Spawns an event-loop bound reactive HTTP/WS server |
server_use_event_loop(srv, loop, on_req, on_ws) |
srv: HttpServer, loop: EventLoop |
Binds an existing HttpServer to a non-blocking reactor |
server_close_reactive(srv) |
srv: HttpServer |
Unregisters server watchers and closes all client streams |
| Function | Parameters | Description |
|---|---|---|
websocket(stream, is_server) |
stream: TcpStream, is_server: int |
Wraps a non-blocking stream into a WebSocketConnection |
ws_send(ws, text) |
ws: WebSocketConnection, text: string |
Sends a UTF-8 text message frame |
ws_send_binary(ws, data) |
ws: WebSocketConnection, data: string |
Sends a binary message frame |
ws_ping(ws, data) |
ws: WebSocketConnection, data: string |
Sends an RFC 6455 ping heartbeat frame |
ws_pong(ws, data) |
ws: WebSocketConnection, data: string |
Sends an RFC 6455 pong heartbeat frame |
ws_close(ws, code, reason) |
ws: WebSocketConnection, code: int, reason: string |
Performs clean close handshake |
ws_on_message(ws, callback) |
ws: WebSocketConnection, cb: fn(ws, msg, is_bin) |
Registers message handler callback |
ws_on_close(ws, callback) |
ws: WebSocketConnection, cb: fn(ws, code, reason) |
Registers connection close callback |
ws_on_ping(ws, callback) |
ws: WebSocketConnection, cb: fn(ws, data) |
Registers incoming ping callback |
ws_on_pong(ws, callback) |
ws: WebSocketConnection, cb: fn(ws, data) |
Registers incoming pong callback |
Run all 14 test suites using alya:
alya testRun individual test files:
alya run tests/test_compression.alya
alya run tests/test_protocol.alya
alya run tests/test_router.alya
alya run tests/test_cookies.alyaRun benchmarks:
alya run benches/bench_basic.alyaRun the demo examples:
alya run examples/demo.alya
alya run examples/compression_demo.alyaCheck code formatting:
alya fmt . --checkRun static code linter:
alya lint . --checkContributions are welcome! Please follow these steps:
- Fork the repository and clone it locally
- Install the package tools:
alya install
- Create your feature branch:
git checkout -b feature/my-feature
- Verify tests and code formatting before opening a PR:
alya test alya fmt . --check
- Commit your changes:
git commit -m "feat: add feature description" - Open a Pull Request on GitHub.
This project is licensed under the MIT License - see the LICENSE file for details.