Skip to content

SAP Compatibility

traverse includes a dedicated SAP compatibility layer for connecting to SAP NetWeaver Gateway and SAP S/4HANA OData services, which implement a subset of OData v2 with SAP-specific extensions.

Configuration

import (
    "github.com/jhonsferg/traverse"
    "github.com/jhonsferg/traverse/ext/sap"
)

client := traverse.New(traverse.Config{
    BaseURL:    "https://my.sap.host/sap/opu/odata/sap/API_SALES_ORDER_SRV/",
    Extension:  sap.Extension(),
})

CSRF token handling

SAP services require a CSRF token for all mutating requests (POST, PUT, PATCH, DELETE). The SAP extension fetches and caches the token automatically:

// The extension handles token fetch transparently
order := map[string]any{
    "SalesOrderType": "TA",
    "SoldToParty":    "100001",
}

var created map[string]any
_, err := client.Collection("A_SalesOrder").Create(ctx, order, &created)
// CSRF token was automatically fetched on the first mutating request

SAP message parsing

SAP returns structured error messages in its own format. The extension translates them to standard traverse errors:

_, err := client.Collection("A_SalesOrder").Create(ctx, order, &result)
var sapErr *sap.Error
if errors.As(err, &sapErr) {
    log.Printf("SAP code: %s", sapErr.Code)
    for _, detail := range sapErr.Details {
        log.Printf("  detail: [%s] %s", detail.Code, detail.Message)
    }
}

Function imports (SAP-style)

Call SAP function imports using the typed action helper:

result, err := client.FunctionImport("BAPI_SALESORDER_SIMULATE").
    Param("OrderType", "TA").
    Param("SoldToParty", "100001").
    Execute(ctx)

Batch requests

SAP Gateway supports OData batch but with stricter requirements. The SAP extension handles the --changeset boundary and encoding:

batch := client.Batch()
batch.Create("A_SalesOrder", order1)
batch.Create("A_SalesOrder", order2)
results, err := batch.Execute(ctx)

Authentication

Basic authentication

client := traverse.New(traverse.Config{
    BaseURL:   "https://my.sap.host/sap/opu/odata/...",
    Extension: sap.Extension(),
    Auth: traverse.BasicAuth{
        Username: "sapuser",
        Password: "sappass",
    },
})

SAP OAuth2 (Cloud)

client := traverse.New(traverse.Config{
    BaseURL:   "https://my.sap.host/.../",
    Extension: sap.Extension(),
    Auth: sap.OAuth2{
        TokenURL:     "https://mytenant.authentication.eu10.hana.ondemand.com/oauth/token",
        ClientID:     os.Getenv("SAP_CLIENT_ID"),
        ClientSecret: os.Getenv("SAP_CLIENT_SECRET"),
    },
})

See also