🌐 Packagist API SDK 概览
pkg/client 与 pkg/repository 一起构成了 Composer Skills 项目中访问 Packagist.org 的 纯 Go HTTP 客户端 SDK。它不依赖 PHP、不依赖本地 composer 二进制——所有数据通过 Packagist 的公开 HTTP/JSON API 直接获取,适合在 Go 服务、CI 流水线、监控脚本等任何无法或不需要安装 Composer 运行时的环境中使用。
模块定位
- 📦 包路径:
- 高级门面:
github.com/scagogogo/composer-skills/pkg/client - 底层 HTTP:
github.com/scagogogo/composer-skills/pkg/repository - 领域模型:
github.com/scagogogo/composer-skills/pkg/domain
- 高级门面:
- 🌐 底层机制:标准库
net/http(ComposerClient)/ 第三方go-requests(Repository)发起 HTTPS 请求,响应为 JSON - 🔌 无 PHP 依赖:与 Composer CLI SDK 完全解耦,可单独引入
- ⚡ 两层架构:
ComposerClient是面向业务的高级门面(20 个方法),Repository是更底层的 HTTP 调用层(统计、列表、安全公告、索引下载)
两层架构
| 层 | 类型 | 包 | 职责 | 适合谁 |
|---|---|---|---|---|
| 🌐 高级门面 | client.ComposerClient | pkg/client | 封装 20 个 Packagist 端点,返回强类型 domain.* 结构 | 大多数业务场景 |
| 🏗️ 底层 HTTP | repository.Repository | pkg/repository | 直接对接 Packagist 仓库 API,支持代理、原始字节下载 | 需要自定义端点 / 代理 / 索引文件下载 |
选哪一层?
90% 的场景用 client.NewComposerClient(...) 即可。只有当你需要:① 通过代理访问 Packagist;② 把整个包索引 list.json 落盘成文件;③ 拿到原始 JSON 字节自行解析——才需要直接用 repository 层。
20 个方法分类总览
ComposerClient 共暴露 20 个方法,按下表分 7 类。每类对应一份子文档。
| 分类 | 方法数 | 重点方法 | 子文档 |
|---|---|---|---|
| 📦 包信息 | 5 | GetPackage、GetPackageWithV2Metadata、GetPackageDevVersions、GetPackageStats、GetPackageChanges | package-info |
| 🔍 搜索 | 3 | SearchPackages、SearchPackagesByTags、SearchPackagesByType | search |
| 📊 统计 | 1 | GetStatistics | statistics |
| 🔒 安全公告 | 3 | GetSecurityAdvisories、GetSecurityAdvisoriesForPackages、GetSecurityAdvisoriesSince | advisories |
| 📋 包列表 | 5 | ListPackages、ListPackagesByVendor、ListPackagesByType、ListPackagesWithData、ListPopularPackages | listing |
| 🛠️ 包管理 | 3 | CreatePackage、EditPackage、UpdatePackage(需 API 凭证) | management |
| 🪞 镜像 | — | 官方镜像源参考 | mirrors |
此外,Repository 层 与 Options 文档介绍底层 pkg/repository 的能力。
快速示例
1. 获取一个包的完整信息
go
package main
import (
"fmt"
"log"
"time"
"github.com/scagogogo/composer-skills/pkg/client"
)
func main() {
c := client.NewComposerClient(30 * time.Second)
info, err := c.GetPackage("symfony/console")
if err != nil {
log.Fatalf("获取包信息失败: %v", err)
}
fmt.Printf("包名: %s\n", info.PackageName)
fmt.Printf("描述: %s\n", info.Package.Description)
fmt.Printf("总下载: %d\n", info.Package.Downloads.Total)
}2. 搜索包
go
c := client.NewComposerClient(30 * time.Second)
res, err := c.SearchPackages("logger", 15, 1)
if err != nil {
log.Fatal(err)
}
fmt.Printf("共 %d 条结果\n", res.Total)
for _, r := range res.Results {
fmt.Printf("- %s : %s\n", r.Name, r.Description)
}3. 查指定包的安全公告
go
adv, err := c.GetSecurityAdvisoriesForPackages([]string{"symfony/http-foundation"})
if err != nil {
log.Fatal(err)
}
for pkg, list := range adv.Advisories {
for _, a := range list {
fmt.Printf("[%s] %s (CVE: %s)\n", pkg, a.Title, a.Cve)
}
}4. 带代理的底层调用(Repository 层)
go
repo := repository.NewRepository(repository.Options{
ServerUrl: "https://packagist.org",
Proxy: "http://127.0.0.1:7890",
})
stats, err := repo.Statistics(ctx)设计约定
- 🎯 返回值统一:高级门面方法要么返回
(*domain.XxxResponse, error)(强类型解析),要么返回([]byte, error)(原始 JSON,留给调用方自行解析,如GetPackageWithV2Metadata)。 - ⚠️ 错误包裹:HTTP 失败、状态码非 200、JSON 解析失败均以
fmt.Errorf("failed to ...: %w", err)形式返回,可用errors.Is/As解包。 - 🔌 凭证可选:只有
CreatePackage/EditPackage/UpdatePackage三个写操作需要WithAPICredentials(...),其余读取方法匿名即可。 - ⚙️ 可注入配置:
WithBaseURL、WithRepoURL允许指向自建 Packagist 镜像或 Satis 实例。
下一步
- 🔌 先读 客户端 ComposerClient:搞懂如何创建客户端、设置超时与凭证。
- 📦 再看 包信息:掌握
GetPackage系列方法。 - 🔒 安全相关见 安全公告;统计见 统计。
- 🏗️ 需要代理或下载索引文件见 Repository 层 与 Options。