Skip to content

GraphQL

Igor Sazonov edited this page Sep 8, 2026 · 1 revision

Every Goldsky Subgraph has a GraphQL interface. The SDK’s GraphQL service builds documented public and private endpoint URLs and sends standard GraphQL HTTP requests. Choose the endpoint type based on who should be able to query the subgraph, not merely on convenience.

Public versus private endpoints

Endpoint type URL prefix Authentication Use case
Public /api/public/{project_id}/subgraphs/{name}/{version_or_tag}/gn None Open data, prototypes, or deliberately public frontends.
Private /api/private/{project_id}/subgraphs/{name}/{version_or_tag}/gn Project Bearer token Backend services and data that should be limited to the project.

Goldsky documents a default public-endpoint rate limit of 50 requests per 10 seconds. Public endpoints are intentionally accessible to anyone. Private endpoints require a token belonging to the same project as the subgraph.1

New subgraphs default to public endpoint enabled and private endpoint disabled. An Editor can change endpoint exposure for a version or tag through Goldsky tooling; in the SDK, use Subgraphs.UpdateVersion. See Subgraphs.

Build endpoint URLs

Prefer the helpers when you need to display or pass an endpoint URL to a generic GraphQL client. The helpers escape each path component.

publicURL := client.GraphQL.PublicURL(projectID, "dex-analytics", "prod")
privateURL := client.GraphQL.PrivateURL(projectID, "dex-analytics", "prod")

fmt.Println(publicURL)
// https://api.goldsky.com/api/public/<project>/subgraphs/dex-analytics/prod/gn

Use a tag such as prod when you want consumers to retain a stable endpoint through deployments. Use a version when reproducibility at an exact indexed deployment is more important.

Query a private endpoint

QueryPrivate adds Authorization: Bearer <project-token> automatically. GraphQLRequest supports a query string, variables, and operation name.

request := goldsky.GraphQLRequest{
    OperationName: "RecentTrades",
    Query: `query RecentTrades($first: Int!) {
        trades(first: $first, orderBy: timestamp, orderDirection: desc) {
            id
            timestamp
            amount
        }
    }`,
    Variables: map[string]any{"first": 10},
}

response, err := client.GraphQL.QueryPrivate(ctx, projectID, "dex-analytics", "prod", request)
if err != nil {
    return err // HTTP failure or transport/decode failure
}
if response.HasErrors() {
    for _, graphqlErr := range response.Errors {
        log.Printf("GraphQL error: %s", graphqlErr.Message)
    }
    return fmt.Errorf("query returned GraphQL errors")
}

var data struct {
    Trades []struct {
        ID        string `json:"id"`
        Timestamp string `json:"timestamp"`
        Amount    string `json:"amount"`
    } `json:"trades"`
}
if err := json.Unmarshal(response.Data, &data); err != nil {
    return err
}

The response separates the raw Data, GraphQL Errors, Extensions, HTTP status, and response headers. This lets callers use server-provided pagination or rate-limit metadata without losing the GraphQL protocol semantics.

Query a public endpoint

QueryPublic uses the public URL and sends no project bearer token.

response, err := client.GraphQL.QueryPublic(ctx, projectID, "dex-analytics", "prod", goldsky.GraphQLRequest{
    Query: `{ _meta { block { number } } }`,
})
if err != nil {
    return err
}
if response.HasErrors() {
    return fmt.Errorf("GraphQL errors: %s", response.Errors[0].Message)
}
fmt.Println(string(response.Data))

Never put a private token in a browser bundle as a workaround for a private endpoint. Proxy private GraphQL queries through an authenticated backend or establish a client-facing authorization design that keeps the Goldsky project token server-side.

Use an arbitrary endpoint with Query

Query(ctx, endpoint, request, auth) is available when you already have an endpoint URL or need a custom routing layer. Set auth to true only for a trusted endpoint that should receive the client’s project token.

response, err := client.GraphQL.Query(ctx, privateURL, goldsky.GraphQLRequest{
    Query: `query { _meta { block { number } } }`,
}, true)

Treat the endpoint parameter as a security boundary. Passing an untrusted URL with auth == true could send the project Bearer token to that URL. For ordinary Goldsky endpoints, prefer QueryPublic and QueryPrivate.

Error handling and rate limiting

GraphQL distinguishes transport/HTTP failures from GraphQL execution errors.

Outcome What Query* returns What to do
Valid 2xx GraphQL response with errors err == nil; response.Errors populated Check HasErrors(); decide whether partial data is acceptable.
Non-2xx HTTP response *goldsky.ProblemDetails Inspect status and headers; handle 429 using RetryAfter.
Network/cancellation/malformed JSON *goldsky.TransportError Respect the context and apply an application policy.

The SDK does not use aggressive hidden GraphQL retries. For a read query that may be safely replayed, a calling application can retry a small bounded number of times on 429 or transient transport errors while honoring the overall context deadline.

Query design for application reliability

Use GraphQL variables rather than concatenating user data into a query string. Request only fields the application uses. In a polling application, record the subgraph’s _meta block and deduplicate results at the business layer. For a continuously changing data set, design cursor or block-based pagination in the query rather than repeatedly requesting an unbounded list.

If the product needs an endpoint rollout, use a tag. First deploy and verify a new version, then move the tag; clients that query the tag can switch without editing every configured endpoint URL.

References

Clone this wiki locally