Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/tools/vbuild-examples.v
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const efolders = [
'examples/vweb_orm_jwt',
'examples/vweb_fullstack',
'examples/vanilla_http_server',
'examples/fasthttp',
]

pub fn normalised_vroot_path(path string) string {
Expand Down
71 changes: 71 additions & 0 deletions examples/fasthttp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Fasthttp Example

A simple HTTP server example using the `fasthttp` module from `vlib/fasthttp`.

## Features

- Handles GET and POST requests
- Routes requests to different controllers based on HTTP method and path
- Returns appropriate HTTP responses with status codes and content

## Building

```sh
./v examples/fasthttp
```

## Running

```sh
./examples/fasthttp/fasthttp
```

The server will listen on `http://localhost:3000`

## Testing

### Home endpoint

```sh
curl http://localhost:3000/
```

### Get user by ID

```sh
curl http://localhost:3000/user/123
```

### Create user

```sh
curl -X POST http://localhost:3000/user
```

### 404 response

```sh
curl http://localhost:3000/notfound
```

## File Structure

- `main.v` - Entry point and request router
- `controllers.v` - Request handlers for different routes
- `v.mod` - Module metadata

## Architecture

The example demonstrates:

1. **Request Routing**: The `handle_request()` function routes incoming HTTP requests based on
method and path
2. **Response Handling**: Controllers return HTTP responses with proper headers and status codes
3. **Content Type**: All responses are returned as `[]u8` (byte arrays)

The fasthttp module handles:

- Low-level socket management
- Request parsing
- Connection handling
- Non-blocking I/O with epoll (Linux) or kqueue (macOS)
27 changes: 27 additions & 0 deletions examples/fasthttp/controllers.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module main

fn home_controller() ![]u8 {
response := 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\nHello, World!'
return response.bytes()
}

fn get_user_controller(id string) ![]u8 {
body := 'User ID: ${id}'
content_length := body.len
response := 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
return response.bytes()
}

fn create_user_controller() ![]u8 {
body := 'User created successfully'
content_length := body.len
response := 'HTTP/1.1 201 Created\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
return response.bytes()
}

fn not_found_response() ![]u8 {
body := '404 Not Found'
content_length := body.len
response := 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
return response.bytes()
}
37 changes: 37 additions & 0 deletions examples/fasthttp/main.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module main

import fasthttp

fn handle_request(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()

if method == 'GET' {
if path == '/' {
return home_controller()!
} else if path.starts_with('/user/') {
id := path[6..]
return get_user_controller(id)!
}
} else if method == 'POST' {
if path == '/user' {
return create_user_controller()!
}
}

return not_found_response()!
}

fn main() {
mut server := fasthttp.new_server(fasthttp.ServerConfig{
port: 3000
handler: handle_request
}) or {
eprintln('Failed to create server: ${err}')
return
}

println('Starting fasthttp server on port http://localhost:3000...')

server.run() or { eprintln('error: ${err}') }
}
6 changes: 6 additions & 0 deletions examples/fasthttp/v.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Module {
name: 'fasthttp_example'
description: 'A simple HTTP server example using the fasthttp module'
version: '0.0.1'
license: 'MIT'
}
161 changes: 161 additions & 0 deletions vlib/fasthttp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# 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:
- `epoll` on Linux for efficient connection handling
- `kqueue` on macOS 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 and macOS

## Installation

The module is part of the standard V library. Import it in your V code:

```v
import fasthttp
```

## Quick Start

Here's a minimal HTTP server example:

```v
import fasthttp

fn handle_request(req fasthttp.HttpRequest) ![]u8 {
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()

if path == '/' {
return 'Hello, World!'.bytes()
}

return '404 Not Found'.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 request
- `method: Slice` - The HTTP method (GET, POST, etc.)
- `path: Slice` - The request path
- `version: 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 buffer
- `len: int` - Length of the slice

**Usage:**

```v ignore
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 failed

The handler should extract method and path information from the request and route accordingly.

**Example:**

```v ignore
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.

```v ignore
// Simple text response
return 'Hello, World!'.bytes()

// HTML response
return '<html><body>Hello</body></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.

```sh
./v examples/fasthttp
./examples/fasthttp/fasthttp
```

## Platform Support

- **Linux**: Uses `epoll` for high-performance I/O multiplexing
- **macOS**: Uses `kqueue` for event notification
- **Windows**: Currently not supported

## Performance Considerations

- The `fasthttp` module 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

## 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
Loading
Loading