Skip to content

traverse

A declarative OData v2/v4 client for Go

Go Version License: MIT pkg.go.dev

traverse is a declarative OData v2/v4 client for Go, built on top of relay for HTTP transport. It handles all OData protocol details - pagination, CSRF tokens, ETag concurrency, delta sync, batch requests, async long-running operations - so you can focus on the data.

The name comes from a deliberate design choice: to traverse means to walk through something large one step at a time, without loading it all into memory. That is the library's founding principle - OData collections are paths to walk, not payloads to download. Read the full philosophy →


🚀 Why traverse?

  • Fluent Query Builder

    Compose OData queries with a type-safe builder: $filter, $select, $expand, $orderby, $top, $skip, $count, $search, $apply.

  • Full CRUD + ETags

    Create, Read, Update (PATCH/PUT), Delete with full ETag-aware variants for optimistic concurrency control.

  • :material-track-changes: Entity Change Tracking

    Track field-level changes, emit PATCH bodies with only the dirty fields, and roll back with Discard.

  • Typed Pagination

    Generic Paginator[T] follows @odata.nextLink and $skiptoken automatically.

  • Streaming

    Channel-based streaming for large datasets. Process millions of records at constant memory.

  • Batch Requests

    Compose multi-operation $batch requests with atomic changesets.

  • Delta Sync

    Incremental updates via OData delta links - sync only what changed since last run.

  • Code Generation

    Generate typed Go structs and query builders from any $metadata EDMX document.


🆚 Comparison

Feature traverse go-odata raw http.Client
OData v2 ✅ ✅ manual
OData v4 ✅ partial manual
Fluent query builder ✅ limited manual
ETag concurrency ✅ ❌ manual
Entity change tracking ✅ ❌ ❌
Generic paginator ✅ ❌ manual
Streaming (channels) ✅ ❌ manual
Batch + changesets ✅ ❌ manual
Delta sync ✅ ❌ manual
Async op polling ✅ ❌ manual
Lambda filters ✅ ❌ manual
Deep insert ✅ ❌ manual
CSRF token mgmt ✅ ❌ manual
Code generation ✅ ❌ ❌
SAP compatibility ✅ partial manual

⚡ 30-Second Example

go get github.com/jhonsferg/traverse
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/jhonsferg/traverse"
)

type Product struct {
    ID       int     `json:"ProductID"`
    Name     string  `json:"ProductName"`
    Price    float64 `json:"UnitPrice"`
    Category string  `json:"CategoryName"`
}

func main() {
    client, err := traverse.New(
        traverse.WithBaseURL("https://services.odata.org/V4/Northwind/Northwind.svc"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx := context.Background()

    var products []Product
    err = client.From("Products").
        Filter("UnitPrice gt 20").
        Select("ProductID", "ProductName", "UnitPrice").
        OrderBy("UnitPrice desc").
        Top(10).
        Into(ctx, &products)
    if err != nil {
        log.Fatal(err)
    }

    for _, p := range products {
        fmt.Printf("%s: $%.2f\n", p.Name, p.Price)
    }
}

📚 Documentation

  • Installation - Get started in under a minute
  • Quick Start - Full working examples from connect to delete
  • OData Primer - OData concepts every Go developer needs to know
  • Guides - Deep dives into every feature
  • Code Generation - Generate typed clients from $metadata
  • Extensions - SAP, OAuth2, Prometheus, OpenTelemetry, Cache, GraphQL, Azure Event Grid, Offline Store, Dataverse, OpenAPI Export, Audit Trail
  • CSDL JSON - Parse OData metadata from JSON endpoints
  • Vocabularies - Core and Validation vocabulary annotations
  • traverse-tui - Interactive terminal OData query builder
  • Reference - Full API reference