fasthttp
The fasthttp module is a high-performance HTTP server library for V that provides low-level socket management and non-blocking I/O.
Features
- High Performance: Uses platform-specific I/O multiplexing:
epollon Linux for efficient connection handlingkqueueon macOS and BSD for high-performance event notification
- Non-blocking I/O: Handles multiple concurrent connections efficiently
- Simple API: Easy-to-use request handler pattern
- Cross-platform: Supports Linux, macOS, FreeBSD, OpenBSD, NetBSD and DragonFly
Installation
The module is part of the standard V library. Import it in your V code:
import fasthttp
Quick Start
Here's a minimal HTTP server example:
import fasthttp
fn handle_request(req fasthttp.HttpRequest) ![]u8 {
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
mut body := ''
mut status_line := ''
if path == '/' {
body = 'Hello, World!\n'
status_line = 'HTTP/1.1 200 OK'
} else {
body = '${path} not found\n'
status_line = 'HTTP/1.1 404 Not Found'
}
headers := [
status_line,
'Content-Type: text/plain',
'Content-Length: ${body.len}',
'Connection: close',
]
header_string := headers.join('\r\n')
return '${header_string}\r\n\r\n${body}'.bytes()
}
fn main() {
mut server := fasthttp.new_server(fasthttp.ServerConfig{
port: 3000
handler: handle_request
}) or {
eprintln('Failed to create server: ${err}')
return
}
println('Server listening on http://localhost:3000')
server.run() or { eprintln('error: ${err}') }
}
API Reference
HttpRequest Struct
Represents an incoming HTTP request.
Fields:
buffer: []u8- The raw request buffer containing the complete HTTP requestmethod: Slice- The HTTP method (GET, POST, etc.)path: Slice- The request pathversion: Slice- The HTTP version (e.g., "HTTP/1.1")client_conn_fd: int- Internal socket file descriptor
Slice Struct
Represents a slice of the request buffer.
Fields:
start: int- Starting index in the bufferlen: int- Length of the sliceUsage:method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr() path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
Request Handler Pattern
The handler function receives an HttpRequest and must return either:
[]u8- A byte array containing the HTTP response body- An error if processing failedThe handler should extract method and path information from the request and route accordingly.Example:
fn my_handler(req fasthttp.HttpRequest) ![]u8 { method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr() path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr() match method { 'GET' { if path == '/' { return 'Home page'.bytes() } } 'POST' { if path == '/api/data' { return 'Data received'.bytes() } } else {} } return '404 Not Found'.bytes() }
Response Format
Responses should be returned as byte arrays. The server will send them directly to the client as HTTP response bodies.
// Simple text response
return 'Hello, World!'.bytes()
// HTML response
return '</html>'.bytes()
// JSON response
return '{"message": "success"}'.bytes()
Example
See the complete example in examples/fasthttp/ for a more
detailed server implementation with multiple routes and controllers.
./v examples/fasthttp
./examples/fasthttp/fasthttp
Platform Support
- Linux: Uses
epollfor high-performance I/O multiplexing - macOS: Uses
kqueuefor event notification - Windows: Currently not supported
Performance Considerations
- The
fasthttpmodule is designed for high throughput and low latency - Handler functions should be efficient; blocking operations will affect other connections
- Use goroutines within handlers if you need to perform long-running operations without blocking the I/O loop
Request-scoped allocation with -prealloc
When an application is compiled with -prealloc, fasthttp starts a scoped
prealloc arena for each request before decoding the HTTP request and before
calling the request handler. All V allocations made by the request parser, the
handler, and code called by the handler use that request arena while the handler
is running.
The arena is freed as a unit after the response no longer needs request-owned
data. On Linux the normal response path sends the response synchronously, then
ends the request arena. On macOS and BSD the response buffer can be kept by the
connection until kqueue finishes writing it; in that case fasthttp detaches
the scope from the request thread and frees it after the write completes.
This means request-local V allocations are cheap bump-pointer allocations, and
freeing them does not require walking individual objects. Startup state, server
state, and allocations made directly by C libraries are not part of a request
arena. If a handler starts V spawn work while the request scope is active, the
generated thread wrapper retains that scope until the spawned function returns;
void spawned functions also run inside their own scoped arena, which is freed at
thread exit. Manual takeover responses transfer ownership to user code and
currently abandon the request arena, so long-lived takeover handlers should
manage their own allocation lifetime explicitly.
To inspect request arena usage while developing, build with:
v -prealloc -d trace_prealloc run .
Notes
- HTTP headers are currently not parsed; the entire request is available in the buffer
- Only the request method, path, and version are parsed automatically
- Response status codes and headers must be manually constructed if needed
- The module provides low-level access for maximum control and performance