Skip to content

Examples

Hello World

A minimal server with two unary methods — greet and add. Supports both stdio and HTTP transports.

// © Copyright 2025-2026, Query.Farm LLC - https://query.farm
// SPDX-License-Identifier: Apache-2.0

package main

import (
    "context"
    "fmt"
    "net"
    "net/http"
    "os"

    "github.com/Query-farm/vgi-rpc-go/vgirpc"
)

type GreetParams struct {
    Name string `vgirpc:"name"`
}

type AddParams struct {
    A float64 `vgirpc:"a"`
    B float64 `vgirpc:"b"`
}

func main() {
    server := vgirpc.NewServer()

    vgirpc.Unary(server, "greet", func(_ context.Context, ctx *vgirpc.CallContext, p GreetParams) (string, error) {
        return "Hello, " + p.Name + "!", nil
    })

    vgirpc.Unary(server, "add", func(_ context.Context, ctx *vgirpc.CallContext, p AddParams) (float64, error) {
        return p.A + p.B, nil
    })

    if len(os.Args) > 1 && os.Args[1] == "--http" {
        httpServer := vgirpc.NewHttpServer(server)

        listener, err := net.Listen("tcp", "127.0.0.1:0")
        if err != nil {
            fmt.Fprintf(os.Stderr, "failed to listen: %v\n", err)
            os.Exit(1)
        }
        port := listener.Addr().(*net.TCPAddr).Port
        fmt.Printf("PORT:%d\n", port)
        os.Stdout.Sync()

        if err := http.Serve(listener, httpServer); err != nil {
            fmt.Fprintf(os.Stderr, "http serve error: %v\n", err)
            os.Exit(1)
        }
    } else {
        server.RunStdio()
    }
}

Run it:

# Build and run with stdio transport
go build -o hello-world ./examples/hello_world/
./hello-world

# Or with HTTP transport
./hello-world --http

Math Service

A more complete example with all four method types: unary (add, multiply), producer (countdown), and exchange (running_sum).

// © Copyright 2025-2026, Query.Farm LLC - https://query.farm
// SPDX-License-Identifier: Apache-2.0

package main

import (
    "context"
    "fmt"
    "net"
    "net/http"
    "os"

    "github.com/apache/arrow-go/v18/arrow"
    "github.com/apache/arrow-go/v18/arrow/array"
    "github.com/apache/arrow-go/v18/arrow/memory"

    "github.com/Query-farm/vgi-rpc-go/vgirpc"
)

func init() {
    // Register state types for gob serialization (needed for HTTP transport).
    vgirpc.RegisterStateType(&CountdownState{})
    vgirpc.RegisterStateType(&RunningSumState{})
}

// --- Parameter structs ---

type AddParams struct {
    A float64 `vgirpc:"a"`
    B float64 `vgirpc:"b"`
}

type MultiplyParams struct {
    A float64 `vgirpc:"a"`
    B float64 `vgirpc:"b"`
}

type CountdownParams struct {
    Start int64 `vgirpc:"start"`
}

type RunningSumParams struct {
    Initial float64 `vgirpc:"initial,default=0"`
}

// --- Schemas ---

var CountdownOutputSchema = arrow.NewSchema([]arrow.Field{
    {Name: "value", Type: arrow.PrimitiveTypes.Int64},
}, nil)

var RunningSumInputSchema = arrow.NewSchema([]arrow.Field{
    {Name: "value", Type: arrow.PrimitiveTypes.Float64},
}, nil)

var RunningSumOutputSchema = arrow.NewSchema([]arrow.Field{
    {Name: "sum", Type: arrow.PrimitiveTypes.Float64},
}, nil)

// --- Producer state: countdown ---

type CountdownState struct {
    Current int64
}

func (s *CountdownState) Produce(_ context.Context, out *vgirpc.OutputCollector, _ *vgirpc.CallContext) error {
    if s.Current < 0 {
        return out.Finish()
    }
    mem := memory.NewGoAllocator()
    b := array.NewInt64Builder(mem)
    defer b.Release()
    b.Append(s.Current)
    arr := b.NewArray()
    defer arr.Release()

    if err := out.EmitArrays([]arrow.Array{arr}, 1); err != nil {
        return err
    }
    s.Current--
    return nil
}

// --- Exchange state: running_sum ---

type RunningSumState struct {
    Sum float64
}

func (s *RunningSumState) Exchange(_ context.Context, input arrow.RecordBatch, out *vgirpc.OutputCollector, _ *vgirpc.CallContext) error {
    valueCol := input.Column(0).(*array.Float64)
    for i := int64(0); i < input.NumRows(); i++ {
        s.Sum += valueCol.Value(int(i))
    }

    mem := memory.NewGoAllocator()
    b := array.NewFloat64Builder(mem)
    defer b.Release()
    b.Append(s.Sum)
    arr := b.NewArray()
    defer arr.Release()

    return out.EmitArrays([]arrow.Array{arr}, 1)
}

// --- Main ---

func main() {
    server := vgirpc.NewServer()

    // Unary: add two numbers
    vgirpc.Unary(server, "add", func(_ context.Context, _ *vgirpc.CallContext, p AddParams) (float64, error) {
        return p.A + p.B, nil
    })

    // Unary: multiply two numbers
    vgirpc.Unary(server, "multiply", func(_ context.Context, _ *vgirpc.CallContext, p MultiplyParams) (float64, error) {
        return p.A * p.B, nil
    })

    // Producer: countdown from start to 0
    vgirpc.Producer(server, "countdown", CountdownOutputSchema,
        func(_ context.Context, _ *vgirpc.CallContext, p CountdownParams) (*vgirpc.StreamResult, error) {
            return &vgirpc.StreamResult{
                OutputSchema: CountdownOutputSchema,
                State:        &CountdownState{Current: p.Start},
            }, nil
        })

    // Exchange: running sum of input values
    vgirpc.Exchange(server, "running_sum", RunningSumOutputSchema, RunningSumInputSchema,
        func(_ context.Context, _ *vgirpc.CallContext, p RunningSumParams) (*vgirpc.StreamResult, error) {
            return &vgirpc.StreamResult{
                OutputSchema: RunningSumOutputSchema,
                State:        &RunningSumState{Sum: p.Initial},
            }, nil
        })

    if len(os.Args) > 1 && os.Args[1] == "--http" {
        httpServer := vgirpc.NewHttpServer(server)

        listener, err := net.Listen("tcp", "127.0.0.1:0")
        if err != nil {
            fmt.Fprintf(os.Stderr, "failed to listen: %v\n", err)
            os.Exit(1)
        }
        port := listener.Addr().(*net.TCPAddr).Port
        fmt.Printf("PORT:%d\n", port)
        os.Stdout.Sync()

        if err := http.Serve(listener, httpServer); err != nil {
            fmt.Fprintf(os.Stderr, "http serve error: %v\n", err)
            os.Exit(1)
        }
    } else {
        server.RunStdio()
    }
}

Python Client

The math service includes a Python client that demonstrates calling all method types across both transports:


Run the demo:

# Build the server
go build -o math-service ./examples/math_service/

# Run the Python client (requires vgi_rpc package)
source /path/to/vgi-rpc/.venv/bin/activate
python examples/math_service/client.py