Skip to content

hero.heroserver #

HeroServer

HeroServer is a secure web server built in V, designed for public key-based authentication and serving OpenRPC APIs and their documentation.

Features

  • Public Key Authentication: Secure access using cryptographic signatures.
  • OpenRPC Integration: Serve APIs defined with the OpenRPC specification.
  • Automatic Documentation: Generates HTML documentation from your OpenRPC schemas.
  • Session Management: Manages authenticated user sessions.
  • CORS Support: Configurable Cross-Origin Resource Sharing for frontend integration.
  • Extensible: Register multiple, independent handlers for different API groups.

Usage

import incubaid.herolib.hero.heroserver
import incubaid.herolib.schemas.openrpc

fn main() {
    // 1. Create a new server instance with CORS support
    mut server := heroserver.new(
        port: 8080
        cors_enabled: true
        allowed_origins: ['http://localhost:5173'] // Frontend dev server
    )!

    // 2. Create and register your OpenRPC handlers
    //    These handlers must conform to the `openrpc.OpenRPCHandler` interface.
    calendar_handler := create_calendar_handler() // Your implementation
    server.register_handler('calendar', calendar_handler)!

    task_handler := create_task_handler() // Your implementation
    server.register_handler('tasks', task_handler)!

    // 3. Start the server
    server.start()! // This call blocks and starts serving requests
}

API Endpoints

  • HTML Homepage: GET / - Returns HTML homepage with server information
  • JSON Handler Info: GET /json/{handler_type} - Returns handler information in JSON format
  • API Calls: POST /api/{handler_type}
  • Documentation: GET /doc/{handler_type}
  • Markdown Docs: GET /md/{handler_type} - Returns documentation in markdown format

Authentication Flow

  1. Register Public Key: POST /auth/register
  • Body: {"pubkey": "your_public_key"}
  1. Request Challenge: POST /auth/authreq
  • Body: {"pubkey": "your_public_key"}
  • Returns a unique challenge string.
  1. Submit Signature: POST /auth/auth
  • Sign the challenge from step 2 with your private key.
  • Body: {"pubkey": "your_public_key", "signature": "your_signature"}
  • Returns a session key.

All subsequent API calls must include the session key in the Authorization header:

Authorization: Bearer {session_key}

fn doc_spec_from_openrpc #

fn doc_spec_from_openrpc(openrpc_spec openrpc.OpenRPC, handler_type string) !DocSpec

doc_spec_from_openrpc converts an OpenRPC specification to a documentation-friendly DocSpec. Processes all methods, parameters, and results with proper type extraction and example generation. Returns error if handler_type is empty or if OpenRPC spec is invalid.

fn doc_spec_from_openrpc_with_config #

fn doc_spec_from_openrpc_with_config(openrpc_spec openrpc.OpenRPC, config DocConfig) !DocSpec

doc_spec_from_openrpc_with_config converts an OpenRPC specification with custom configuration

fn new #

fn new(config HeroServerConfig) !&HeroServer

Create a new HeroServer instance

struct APIRequest #

struct APIRequest {
pub:
	session_key string
	method      string
	params      map[string]string
}

API request wrapper

struct AuthChallenge #

struct AuthChallenge {
pub mut:
	pubkey     string
	challenge  string // unique hashed challenge
	created_at time.Time
	expires_at time.Time
}

Authentication challenge data

struct AuthDocInfo #

struct AuthDocInfo {
pub mut:
	enabled bool
	steps   []AuthStep
}

AuthDocInfo contains authentication flow information

struct AuthRequest #

struct AuthRequest {
pub:
	pubkey string
}

struct AuthResponse #

struct AuthResponse {
pub:
	challenge string
}

struct AuthStep #

struct AuthStep {
pub mut:
	number      int
	title       string
	method      string
	endpoint    string
	description string
	example     string
}

AuthStep represents a single step in the authentication flow

struct AuthSubmitRequest #

struct AuthSubmitRequest {
pub:
	pubkey    string
	signature string // signed challenge
}

struct AuthSubmitResponse #

struct AuthSubmitResponse {
pub:
	session_key string
}

struct Context #

struct Context {
	veb.Context
}

Context struct for VEB

struct DocConfig #

struct DocConfig {
pub mut:
	base_url     string = 'http://localhost:8080'
	handler_type string
	auth_enabled bool = true
}

DocConfig holds configuration for documentation generation

struct DocMethod #

struct DocMethod {
pub mut:
	name             string
	summary          string
	description      string
	params           []DocParam
	result           DocParam
	example_request  string
	example_response string
	endpoint_url     string
	curl_example     string
}

DocMethod holds the information for a single method to be displayed.

struct DocObject #

struct DocObject {
pub mut:
	name        string
	description string
	methods     []DocMethod
}

DocObject represents a logical grouping of methods.

struct DocParam #

struct DocParam {
pub mut:
	name        string
	description string
	type_info   string
	required    bool
	example     string
}

DocParam represents a parameter or result in the documentation

struct DocSpec #

struct DocSpec {
pub mut:
	info      openrpc.Info
	methods   []DocMethod
	objects   []DocObject
	auth_info AuthDocInfo
	base_url  string // Dynamic base URL for examples
}

DocSpec is the main object passed to the documentation template.

struct EndpointsJSON #

struct EndpointsJSON {
pub:
	api_pattern           string
	documentation_pattern string
	markdown_pattern      string
	home_json             string
	home_html             string
}

struct ExampleRequestJSON #

struct ExampleRequestJSON {
pub:
	method      string
	url         string
	headers     map[string]string
	body        string
	description string
}

struct FeatureJSON #

struct FeatureJSON {
pub:
	title       string
	description string
	icon        string
}

struct HandlerInfoJSON #

struct HandlerInfoJSON {
pub:
	name         string
	title        string
	description  string
	version      string
	api_endpoint string
	doc_endpoint string
	md_endpoint  string
	methods      []MethodInfoJSON
}

struct HeroServer #

struct HeroServer {
	veb.Middleware[Context]
mut:
	port            int
	host            string
	crypto_client   &herocrypt.HeroCrypt
	sessions        map[string]Session          // sessionkey -> Session
	handlers        map[string]&openrpc.Handler // handlertype -> handler
	challenges      map[string]AuthChallenge
	cors_enabled    bool
	allowed_origins []string
	logger          logger.Logger // Logger instance with dual output
	start_time      i64           // Server start timestamp for uptime calculation
pub mut:
	auth_enabled bool = true // Whether authentication is required
}

Main server struct

fn (HeroServer) api_handler #

fn (mut server HeroServer) api_handler(mut ctx Context, handler_type string) veb.Result

fn (HeroServer) auth_handler #

fn (mut server HeroServer) auth_handler(mut ctx Context, action string) !veb.Result

fn (HeroServer) auth_request #

fn (mut server HeroServer) auth_request(pubkey string) !AuthResponse

Request authentication challenge

fn (HeroServer) auth_submit #

fn (mut server HeroServer) auth_submit(pubkey string, signature string) !AuthSubmitResponse

Submit signed challenge for authentication

fn (HeroServer) before_request #

fn (mut server HeroServer) before_request(mut ctx Context)

before_request is called before every request

fn (HeroServer) doc_handler #

fn (mut server HeroServer) doc_handler(mut ctx Context, handler_type string) veb.Result

fn (HeroServer) health_handler #

fn (mut server HeroServer) health_handler(mut ctx Context) veb.Result

Health check endpoint

fn (HeroServer) home_handler #

fn (mut server HeroServer) home_handler(mut ctx Context) veb.Result

Home page handler - returns HTML homepage for GET, handles JSON-RPC for POST

fn (HeroServer) json_handler #

fn (mut server HeroServer) json_handler(mut ctx Context, handler_type string) veb.Result

JSON server info handler

fn (HeroServer) log #

fn (mut server HeroServer) log(params ServerLogParams)

Log a message using the server's logger

fn (HeroServer) md_handler #

fn (mut server HeroServer) md_handler(mut ctx Context, handler_type string) veb.Result

fn (HeroServer) register #

fn (mut server HeroServer) register(pubkey string) !

Register a public key (currently just validates format)

fn (HeroServer) register_handler #

fn (mut server HeroServer) register_handler(handler_type string, handler &openrpc.Handler) !

Register an OpenRPC handler

fn (HeroServer) start #

fn (mut server HeroServer) start() !

Start the server

fn (HeroServer) validate_session #

fn (mut server HeroServer) validate_session(session_key string) !Session

Validate session key

struct HeroServerConfig #

@[params]
struct HeroServerConfig {
pub mut:
	port           int    = 9977
	host           string = 'localhost'
	log_path       string = '/tmp/heroserver_logs'
	console_output bool   = true // Enable console logging by default

	// flags
	auth_enabled bool = true // Whether to enable authentication
	// CORS configuration
	cors_enabled    bool     = true  // Whether to enable CORS
	allowed_origins []string = ['*'] // Allowed origins for CORS, default allows all
	// Optional crypto client, will create default if not provided
	crypto_client ?&herocrypt.HeroCrypt
}

Main server configuration

struct HomePageData #

struct HomePageData {
pub mut:
	base_url     string
	handlers     map[string]&openrpc.Handler
	auth_enabled bool
	host         string
	port         int
}

Home page data for template rendering

struct MethodInfoJSON #

struct MethodInfoJSON {
pub:
	name        string
	summary     string
	description string
}

struct QuickStartJSON #

struct QuickStartJSON {
pub:
	description string
	example     ExampleRequestJSON
}

struct RegisterRequest #

struct RegisterRequest {
pub:
	pubkey string
}

Authentication request structures

struct ServerInfoJSON #

struct ServerInfoJSON {
pub:
	server_name  string
	version      string
	description  string
	base_url     string
	host         string
	port         int
	auth_enabled bool
	handlers     []HandlerInfoJSON
	endpoints    EndpointsJSON
	features     []FeatureJSON
	quick_start  QuickStartJSON
}

JSON response structures for homepage

struct ServerLogParams #

@[params]
struct ServerLogParams {
pub:
	message string
	level   logger.LogType = .stdout  // Default to info level
	cat     string         = 'server' // Default category
}

Convenient logging method for the server

struct Session #

struct Session {
pub mut:
	session_key   string
	pubkey        string
	created_at    time.Time
	last_activity time.Time
	expires_at    time.Time
}

Active session data