Skip to content

📊 get_statistics — Retrieve Repository Statistics

This example demonstrates how to call the Packagist repository endpoint to obtain total downloads, package count, and version count in one shot, and compute derived metrics from them.

Example Positioning

📚 This is a beginner example for "remote data reading + simple data analysis," positioned as follows:

  • 🎯 Learning objective: Master the full flow of pulling repository-level statistics via the Repository client.
  • 🔗 Corresponding SDK method: repository.Repository.Statistics(ctx), which returns domain.StatisticsResponse.
  • 🧩 Scenario: Display the scale of the Packagist ecosystem on a dashboard, record daily total-change trends, and evaluate a self-hosted mirror's coverage of the official repository.
  • 📈 Extension: The example also demonstrates how to compute derived metrics like "average downloads per package" and "average versions per package" from raw totals, laying the groundwork for trend analysis.

Full Code

go
package main

import (
	"context"
	"fmt"

	"github.com/scagogogo/composer-skills/pkg/repository"
)

func main() {
	// Step 1: Initialize the repository client
	// Set repository options, pointing to the official repository
	options := &repository.Options{
		ServerUrl: "https://packagist.org",
	}

	// Create the repository client
	// In real code there may be a dedicated constructor
	repo := &repository.Repository{}

	// Only to avoid the unused-variable warning
	_ = options

	// Step 2: Get statistics
	fmt.Println("Fetching Composer repository statistics...")

	// Create a context
	ctx := context.Background()

	// Call the Statistics API to get statistics
	stats, err := repo.Statistics(ctx)
	if err != nil {
		fmt.Printf("Failed to fetch statistics: %v\n", err)
		return
	}

	// Step 3: Process and display the statistics
	fmt.Println("\nRepository statistics:")
	fmt.Printf("  Total downloads: %d\n", stats.Totals.Downloads)
	fmt.Printf("  Package count: %d\n", stats.Totals.Packages)
	fmt.Printf("  Version count: %d\n", stats.Totals.Versions)

	// Step 4: Compute some derived metrics (example)
	if stats.Totals.Packages > 0 {
		// Compute average downloads per package
		avgDownloadsPerPackage := float64(stats.Totals.Downloads) / float64(stats.Totals.Packages)
		fmt.Printf("\nAverage downloads per package: %.2f\n", avgDownloadsPerPackage)

		// Compute average versions per package
		avgVersionsPerPackage := float64(stats.Totals.Versions) / float64(stats.Totals.Packages)
		fmt.Printf("Average versions per package: %.2f\n", avgVersionsPerPackage)
	}

	// Step 5: Format numbers for human readability (example)
	formattedDownloads := formatNumber(stats.Totals.Downloads)
	fmt.Printf("\nFormatted downloads: %s\n", formattedDownloads)
}

// formatNumber formats a number into a readable form, adding thousands separators
func formatNumber(n int64) string {
	str := fmt.Sprintf("%d", n)
	result := ""

	// Add a comma every three digits from the right
	for i, c := range str {
		if i > 0 && (len(str)-i)%3 == 0 {
			result += ","
		}
		result += string(c)
	}

	return result
}

Code Walkthrough

  • ⚙️ Initialize the repository client: construct repository.Options and point ServerUrl at https://packagist.org, then create the client with &repository.Repository{}. Production code should use a dedicated constructor so that HTTP timeouts, proxies, and retry strategies can be injected.
  • 🌐 Create a context: use context.Background() as the root context for the request. In long-running services, switch to context.WithTimeout with timeout/cancellation to avoid blocking for a long time when Packagist responds slowly.
  • 📥 Call Statistics: repo.Statistics(ctx) returns *domain.StatisticsResponse in one shot; its Totals field aggregates the three core totals: Downloads, Packages, and Versions. Always check err — network jitter or rate limiting can cause the request to fail.
  • 🖨️ Display raw totals: read the three stats.Totals.* fields directly and format them for output. This is the most common data source for dashboard "overview cards."
  • 🧮 Compute derived metrics: under the guard Packages > 0, use Downloads / Packages and Versions / Packages to get "average downloads per package" and "average versions per package" for横向 comparing ecosystem health.
  • ✍️ Human-friendly number formatting: formatNumber implements thousands-separator insertion itself, making large numbers readable (e.g. 25,000,000,000). In production, you can swap in an internationalization library like golang.org/x/text/message to also support locale-specific grouping symbols.
  • 🛡️ Error handling: after getting err, print and return to avoid dereferencing a nil stats. The example omits retry and logging for simplicity; in real applications, add backoff retry and structured logging.

How to Run

bash
# Enter the example directory
cd /home/cc11001100/github/scagogogo/composer-skills/examples/get_statistics

# Run directly (this will make a real API call; avoid running it frequently)
go run main.go

⚠️ Note: This example makes a real request to https://packagist.org/statistics.json. Please control the call frequency to avoid burdening the target server; in a network-restricted environment, configure a proxy in Options.

SDK Methods Involved

Method NamePackageDescriptionDoc Link
Statisticspkg/repositoryGet overall Packagist repository statistics (downloads/package count/version count)get-statistics
StatisticsResponse / Totalspkg/domainStatistics response struct and nested totalsstatistics
Optionspkg/repositoryRepository client config (ServerUrl, etc.)options

Going Further

  • 📉 Trend recording: write the daily-pulled Totals into a time-series database (e.g. Prometheus / InfluxDB) and plot a download-growth curve to quantify the ecosystem's expansion rate.
  • 🪞 Mirror coverage assessment: compare your self-hosted Satis / private mirror's total package count against the official Packages total to derive a coverage metric that guides your mirror sync strategy.
  • 🔁 Scheduled collection: use cron or a Kubernetes CronJob to call Statistics once an hour, pair it with context.WithTimeout to cap each request's duration, and apply backoff retry on failure.
  • 🧱 Per-package statistics extension: after obtaining repository totals, you can further call the per-package PackageStats endpoint to compute a package's share of total downloads and identify the "head packages" in the ecosystem.
  • 🌍 Internationalized numbers: replace formatNumber with message.NewPrinter(language.SimplifiedChinese) from golang.org/x/x/text/message to automatically adapt thousands/decimal separators to each region.
  • 📊 Structured output: serialize StatisticsResponse to JSON and write it to a file or push it to a monitoring dashboard for downstream systems to consume, rather than only printing to the terminal.

Released under the MIT License