Help us shape the future of Go! Take the 2026 Go Developer Survey

wikigo

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 21, 2026 License: MIT Imports: 13 Imported by: 0

README

wikigo

wikigo is a , type-safe Go SDK for the Wikimedia REST API. It wraps the API with proper typing, context propagation, error wrapping, robust rate limiting, and backoff retry logic.


Features

  • Functional Options: Modular and backward-compatible client initialization (e.g. custom subdomains, timeouts, user-agents, and retries).
  • Context-Aware: context.Context is passed as the first parameter to all public API calls to support cancellations, timeouts, and deadlines.
  • Resource-Scoped Sub-Clients: Intuitive structure matching the API resource layout (client.Pages, client.Search, client.Revisions, client.Media).
  • Custom Transport (retryTransport): An invisible http.RoundTripper layer handling:
    • Token Bucket Rate Limiting: Smooth request pacing using golang.org/x/time/rate.
    • Exponential Backoff & Jitter: Random ±20% jitter to prevent thundering herd problems.
    • Selective Retries: Retries only transient server errors (HTTP 503) and rate-limit blocks (HTTP 429), respecting the Retry-After header.
  • Dedicated Errors Package: Explicit error handling with status code preservation (WikiError struct) and sentinel errors for easy comparisons (errors.Is).
  • No External Web Frameworks: Built purely on top of Go's standard library and the official x/time package.

Installation

go get github.com/saluja-ji/wikigo

Directory Layout

├── errors/
│   └── errors.go       # Sentinel errors and WikiError definition
├── models/
│   └── models.go       # Strongly typed JSON representation structs
├── client.go           # Core client and sub-client definitions
├── options.go          # Configuration options (Functional Options)
├── transport.go        # Custom retry & rate limiting http.RoundTripper
├── pages.go            # Pages sub-client implementations
├── search.go           # Search sub-client implementations
├── revisions.go        # Revisions sub-client implementations
└── media.go            # Media sub-client implementations

Getting Started

Here is a quick example of constructing the client and utilizing its sub-clients:

package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/saluja-ji/wikigo"
	wikierrors "github.com/saluja-ji/wikigo/errors"
	"golang.org/x/time/rate"
)

func main() {
	// 1. Initialize client using Functional Options
	client := wikigo.NewClient(
		wikigo.WithLanguage("en"),
		wikigo.WithProject("wikipedia"),
		wikigo.WithTimeout(10*time.Second),
		wikigo.WithRateLimit(rate.Limit(10), 10), // Limit to 10 req/sec
		wikigo.WithMaxRetries(3),
	)

	ctx := context.Background()

	// 2. Fetch page summary details
	summary, err := client.Pages.GetSummary(ctx, "Earth")
	if err != nil {
		handleError(err)
		return
	}
	fmt.Printf("Summary of %s: %s\n", summary.DisplayTitle, summary.Description)

	// 3. Search for pages matching a query
	searchResp, err := client.Search.Pages(ctx, "Go (programming language)", 3)
	if err != nil {
		handleError(err)
		return
	}
	for _, page := range searchResp.Pages {
		fmt.Printf("Search Match: %s (ID: %d)\n", page.Title, page.ID)
	}
}

func handleError(err error) {
	var wikiErr *wikierrors.WikiError
	if errors.As(err, &wikiErr) {
		fmt.Printf("API Error: [HTTP %d] %v\n", wikiErr.StatusCode, wikiErr.Err)
	} else {
		fmt.Printf("Standard Error: %v\n", err)
	}
}

Client API Reference

client.Pages
  • Get(ctx, title): Retrieves basic page metadata (*models.Page) from /page/{title}/bare using Core REST API.
  • GetSummary(ctx, title): Retrieves a quick, preview-friendly summary (*models.Summary) from /page/summary/{title} using the Legacy/Summary API.
  • Pages(ctx, query, limit): Queries matching articles (*models.SearchResponse) containing title or content terms.
client.Revisions
  • List(ctx, title, limit, olderThan): Fetches history edits list (*models.RevisionList). Does not auto-paginate. You must pass the returned Continue token cursor back into consecutive list requests to retrieve older segments.
client.Media
  • GetFile(ctx, title): Retrieves file detail metadata (*models.File) from /file/{title} for media files (the title must contain the File: prefix).

Detailed Design Details

Rate Limiting

A token bucket rate limiter is embedded directly inside retryTransport. The client blocks appropriately using Wait() before a request goes out:

if err := t.limiter.Wait(req.Context()); err != nil {
    return nil, fmt.Errorf("rate limiter wait: %w", err)
}

This is fully transparent to callers, ensuring you stay within Wikimedia limits without doing any custom interval spacing.

Transparent Retries & Retry-After

If a request encounters a rate limit (HTTP 429) or a service outage (HTTP 503), the client automatically starts a retry cycle:

  1. It parses and respects the Retry-After header if it's sent back as part of a 429 (supports both integer seconds and HTTP dates).
  2. If Retry-After is missing, it calculates a backoff with exponential scaling: $$\text{backoff} = 1\text{s} \times 2^{\text{attempt}}$$
  3. Applies a $\pm20%$ randomized jitter to the backoff to prevent thundering herd locks.
  4. Permanent errors like 404 Not Found, 400 Bad Request, or 401 Unauthorized return immediately without any retry loops.
Preserved Error Hierarchy

Any failure >= 400 returns a wrapped WikiError struct:

type WikiError struct {
    StatusCode int    // Preserves original HTTP status code (e.g. 404)
    Err        error  // Standard Sentinel Error
    Message    string // Descriptive payload from the API body
}

You can inspect errors directly using errors.Is to check for specific error states:

  • errors.Is(err, wikierrors.ErrNotFound)
  • errors.Is(err, wikierrors.ErrRateLimited)
  • errors.Is(err, wikierrors.ErrUnauthorized)

Running Tests

All unit tests compile and run deterministically against mock servers. No live requests are ever executed during the tests.

To run the unit tests:

go test -v ./...

Documentation

Overview

Package wikigo provides a production-quality, type-safe Go SDK for the Wikimedia REST API. It wraps pages, search, revisions, and media APIs with context propagation, structured error handling, rate limiting, and exponential backoff retry logic.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// Pages provides operations related to reading page content and summaries.
	Pages *PagesClient
	// Search provides endpoints to query the wiki index.
	Search *SearchClient
	// Revisions provides endpoints to inspect page history revisions.
	Revisions *RevisionsClient
	// Media provides operations to retrieve media file details.
	Media *MediaClient
	// contains filtered or unexported fields
}

Client is the primary entrypoint for the Wikimedia REST API SDK. It organizes API methods into resource-scoped sub-clients.

func NewClient

func NewClient(opts ...Option) *Client

NewClient constructs a new wikigo client using the provided functional options.

type MediaClient

type MediaClient struct {
	// contains filtered or unexported fields
}

MediaClient groups API operations related to media files.

func (*MediaClient) GetFile

func (m *MediaClient) GetFile(ctx context.Context, title string) (*models.File, error)

GetFile retrieves metadata and details for a specific media file by its title. It maps to the GET /file/{title} endpoint using the Core REST API. The title should include the "File:" namespace prefix (e.g. "File:The_Blue_Marble.jpg").

type Option

type Option func(*config)

Option represents a configuration function for customizing the client.

func WithBaseURL

func WithBaseURL(url string) Option

WithBaseURL overrides the constructed host URL entirely. Useful for custom deployments or local mock servers during tests. E.g., "http://127.0.0.1:8080".

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient overrides the underlying http.Client used by the SDK. The SDK wraps the client's transport with its own retry and rate-limiting transport.

func WithLanguage

func WithLanguage(lang string) Option

WithLanguage sets the language sub-domain for the Wikimedia project (e.g., "en", "de"). Default is "en".

func WithMaxRetries

func WithMaxRetries(retries int) Option

WithMaxRetries sets the maximum number of retry attempts for failed requests. Only HTTP 429 and 503 errors are retried. Default is 3.

func WithProject

func WithProject(proj string) Option

WithProject sets the Wikimedia project domain (e.g., "wikipedia", "wiktionary", "wikibooks"). Default is "wikipedia".

func WithRateLimit

func WithRateLimit(limit rate.Limit, burst int) Option

WithRateLimit sets the parameters for the client rate limiter. rateLimit specifies the maximum requests per second, and burst specifies the token burst size.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the timeout duration for client-wide request execution. Default is 30 seconds.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent overrides the HTTP User-Agent header value sent on all requests. A descriptive User-Agent is required under the Wikimedia API usage guidelines.

type PagesClient

type PagesClient struct {
	// contains filtered or unexported fields
}

PagesClient groups API operations related to pages.

func (*PagesClient) Get

func (p *PagesClient) Get(ctx context.Context, title string) (*models.Page, error)

Get retrieves metadata for a specific wiki page by its title using the Core REST API. It maps to the GET /page/{title}/bare endpoint.

func (*PagesClient) GetSummary

func (p *PagesClient) GetSummary(ctx context.Context, title string) (*models.Summary, error)

GetSummary retrieves a structured page summary for previews using the legacy REST API. It maps to the GET /page/summary/{title} endpoint.

type RevisionsClient

type RevisionsClient struct {
	// contains filtered or unexported fields
}

RevisionsClient groups API operations related to revisions history.

func (*RevisionsClient) List

func (r *RevisionsClient) List(ctx context.Context, title string, limit int, olderThan string) (*models.RevisionList, error)

List retrieves a segment of the revision history for a specific page. It maps to the GET /page/{title}/history endpoint using the Core REST API. It handles cursor-based pagination explicitly by returning a Continue token.

type SearchClient

type SearchClient struct {
	// contains filtered or unexported fields
}

SearchClient groups API operations related to search.

func (*SearchClient) Pages

func (s *SearchClient) Pages(ctx context.Context, query string, limit int) (*models.SearchResponse, error)

Pages searches for pages matching the query string in title or content. It maps to the GET /search/page endpoint using Core REST API.

Directories

Path Synopsis
Package errors defines standard sentinel errors and structured error types for the wikigo Wikimedia REST API client.
Package errors defines standard sentinel errors and structured error types for the wikigo Wikimedia REST API client.
Package main provides a runnable example of using the wikigo SDK to interact with the live Wikimedia REST API.
Package main provides a runnable example of using the wikigo SDK to interact with the live Wikimedia REST API.
Package models defines the strongly typed data models used by the wikigo Wikimedia REST API client.
Package models defines the strongly typed data models used by the wikigo Wikimedia REST API client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL