SAP Extension¶
The SAP extension (ext/sap) provides compatibility with SAP NetWeaver Gateway and SAP S/4HANA OData services.
Installation¶
Features¶
- Automatic CSRF token fetch and caching
- SAP-specific error message parsing (
innererror/errordetails) - Function import helpers
- x-csrf-token header injection on all mutating requests
- Compatible with SAP Gateway (OData v2) and S/4HANA (OData v4)
Quick start¶
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_PRODUCT_SRV/",
Extension: sap.Extension(),
})
CSRF token lifecycle¶
- On the first mutating request (POST/PUT/PATCH/DELETE), the extension issues a
HEADrequest withX-CSRF-Token: Fetch. - The returned token is cached in memory.
- All subsequent mutating requests include
X-CSRF-Token: <cached>. - On a 403
X-CSRF-Token: Requiredresponse, the token is invalidated and re-fetched automatically.
Error handling¶
var sapErr *sap.Error
if errors.As(err, &sapErr) {
fmt.Println(sapErr.Code)
fmt.Println(sapErr.Message.Value)
for _, d := range sapErr.Details {
fmt.Printf(" %s: %s\n", d.Code, d.Message.Value)
}
}
SAP BTP / XSUAA token exchange¶
The ext/sap package also supports SAP Business Technology Platform (BTP) via the XSUAA identity service, enabling automatic OAuth2 token exchange for cloud-native SAP services.
Parsing VCAP_SERVICES¶
In a Cloud Foundry or BTP environment, service credentials are injected via the VCAP_SERVICES environment variable. Parse them with:
import "github.com/jhonsferg/traverse/ext/sap"
// Read from the environment (defaults to the "xsuaa" binding)
binding, err := sap.ParseVCAPServicesEnv("xsuaa")
if err != nil {
log.Fatal(err)
}
Or supply the JSON string directly:
The returned XSUAABinding contains the ClientID, ClientSecret, TokenURL, optional APIURL, and ZoneID.
Creating a BTP client¶
The easiest path reads VCAP_SERVICES automatically:
client, err := sap.NewBTPClient(ctx, "https://my-service.sap.example.com/odata/")
if err != nil {
log.Fatal(err)
}
Or build from an explicit binding (useful in tests):
NewBTPClientFromBinding validates credentials, performs an initial token fetch to verify connectivity, and returns a fully configured traverse client with OAuth2 token injection and CSRF handling.
BTPTokenProvider¶
BTPTokenProvider wraps the OAuth2 token manager and adds a 30-second error back-off -- repeated failures within the window return the cached error without hammering the token endpoint:
XSUAABinding fields¶
| Field | Description |
|---|---|
ClientID | OAuth2 client ID from the service binding |
ClientSecret | OAuth2 client secret |
TokenURL | Full token endpoint ({url}/oauth/token) |
APIURL | Base URL of the BTP service (optional) |
ZoneID | Identity zone / subaccount ID |