📊 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
Repositoryclient. - 🔗 Corresponding SDK method:
repository.Repository.Statistics(ctx), which returnsdomain.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.Optionsand pointServerUrlathttps://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 tocontext.WithTimeoutwith timeout/cancellation to avoid blocking for a long time when Packagist responds slowly. - 📥 Call Statistics:
repo.Statistics(ctx)returns*domain.StatisticsResponsein one shot; itsTotalsfield aggregates the three core totals:Downloads,Packages, andVersions. Always checkerr— 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, useDownloads / PackagesandVersions / Packagesto get "average downloads per package" and "average versions per package" for横向 comparing ecosystem health. - ✍️ Human-friendly number formatting:
formatNumberimplements thousands-separator insertion itself, making large numbers readable (e.g.25,000,000,000). In production, you can swap in an internationalization library likegolang.org/x/text/messageto also support locale-specific grouping symbols. - 🛡️ Error handling: after getting
err, print andreturnto avoid dereferencing a nilstats. 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 inOptions.
SDK Methods Involved
| Method Name | Package | Description | Doc Link |
|---|---|---|---|
Statistics | pkg/repository | Get overall Packagist repository statistics (downloads/package count/version count) | get-statistics |
StatisticsResponse / Totals | pkg/domain | Statistics response struct and nested totals | statistics |
Options | pkg/repository | Repository client config (ServerUrl, etc.) | options |
Going Further
- 📉 Trend recording: write the daily-pulled
Totalsinto 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
Packagestotal to derive a coverage metric that guides your mirror sync strategy. - 🔁 Scheduled collection: use cron or a Kubernetes CronJob to call
Statisticsonce an hour, pair it withcontext.WithTimeoutto 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
PackageStatsendpoint to compute a package's share of total downloads and identify the "head packages" in the ecosystem. - 🌍 Internationalized numbers: replace
formatNumberwithmessage.NewPrinter(language.SimplifiedChinese)fromgolang.org/x/x/text/messageto automatically adapt thousands/decimal separators to each region. - 📊 Structured output: serialize
StatisticsResponseto 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.