The official Go SDK for the Open Ranking protocol.
go get github.com/Open-Ranking/go-sdkimport (
openranking "github.com/Open-Ranking/go-sdk"
)
client, err := openranking.NewClient("https://example-provider.com", http.DefaultClient)
if err != nil {
log.Fatal(err)
}NewClient fetches and validates the provider's capability document once and caches it. All subsequent calls use the cached capabilities without any extra round-trips.
resp, err := client.RankPubkeys(ctx, openranking.RankPubkeysRequest{
Pubkeys: []string{alicePubkey, bobPubkey},
POV: myPubkey, // rank relative to my social graph
})
if err != nil {
return err
}
for _, r := range resp.Results {
fmt.Printf("%s → %.4f\n", r.Pubkey, r.Rank)
}resp, err := client.StatsPubkey(ctx, openranking.StatsPubkeyRequest{
Pubkey: alicePubkey,
})
fmt.Printf("rank=%.4f followers=%d\n", resp.Rank, *resp.Followers)resp, err := client.RecommendPubkeys(ctx, openranking.RecommendPubkeysRequest{
POV: myPubkey,
Topic: "bitcoin",
Limit: 20,
})resp, err := client.SearchPubkeys(ctx, openranking.SearchPubkeysRequest{
Query: "fiatjaf",
Limit: 10,
})followers, err := client.Followers(ctx, openranking.FollowersRequest{
Pubkey: alicePubkey,
Limit: 50,
})
muters, err := client.Muters(ctx, openranking.MutersRequest{
Pubkey: alicePubkey,
})resp, err := client.CompromisedPubkeys(ctx, openranking.CompromisedPubkeysRequest{
Pubkeys: []string{alicePubkey, bobPubkey},
})
for pk, result := range resp {
fmt.Printf("%s is compromised: %v\n", pk, result)
}Every method accepts optional Option arguments appended after the request struct. Use WithAuth to attach a NWT token to the request:
resp, err := client.RankPubkeys(ctx, openranking.RankPubkeysRequest{
Pubkeys: []string{alicePubkey},
POV: myPubkey,
}, openranking.WithAuth(mySignedEvent))You can also compose multiple options:
resp, err := client.RecommendPubkeys(ctx, req,
openranking.WithAuth(mySignedEvent),
myCustomHeaderOption,
)Option is just func(*http.Request) error, so it's easy to write your own:
func WithAPIKey(key string) openranking.Option {
return func(r *http.Request) error {
r.Header.Set("X-API-Key", key)
return nil
}
}Providers expose one or more algorithms per endpoint. To use a specific one, set the Algorithm field on any request. Leave it empty to use the provider's default.
resp, err := client.RankPubkeys(ctx, openranking.RankPubkeysRequest{
Pubkeys: []string{alicePubkey},
Algorithm: "pagerank-v2",
})Inspect available algorithms from the cached capability document:
caps := client.Capabilities()
for _, algo := range caps.RankPubkeys {
fmt.Printf("id=%-20s pov=%v %s\n", algo.ID, algo.POV, algo.Description)
}To refresh capabilities (e.g. on a schedule):
if err := client.RefreshCapabilities(ctx); err != nil {
log.Println("capabilities refresh failed:", err)
}The mock sub-package provides a test Open Ranking server backed by net/http/httptest. Import it in your tests to spin up a real HTTP server without any external dependencies:
import (
openranking "github.com/Open-Ranking/go-sdk"
"github.com/Open-Ranking/go-sdk/mock"
)
func TestMyCode(t *testing.T) {
caps := openranking.CapabilityDoc{
StatsPubkey: []openranking.Algorithm{{ID: "algo-v1"}},
RankPubkeys: []openranking.Algorithm{{ID: "algo-v1"}},
}
srv := mock.NewServer(caps)
defer srv.Close()
srv.OnRankPubkeys = func(r openranking.RankPubkeysRequest) (openranking.RankPubkeysResponse, error) {
return openranking.RankPubkeysResponse{
Results: []openranking.RankedPubkey{{Pubkey: r.Pubkeys[0], Rank: 1.0}},
}, nil
}
client, err := openranking.NewClient(srv.URL, srv.Client())
// ...
}Endpoints with a nil On* handler return 501 Not Implemented. Handlers can return any *openranking.Error or openranking.Retry value and the mock will write the correct HTTP response.
resp, err := client.StatsPubkey(ctx, req)
var httpErr openranking.Error
var retry openranking.Retry
switch {
case errors.As(err, &httpErr):
fmt.Println("HTTP error", httpErr.Code, httpErr.Reason)
case errors.As(err, &retry):
// result not ready yet — try again after retry.After
time.Sleep(retry.After)
default:
// network or validation error
}