API 文档
使用 Packagist.org API 的最佳实践
- 如果您进行计划任务,请避免在午夜或每小时 XX:00 运行任务。大多数人都会这样做,我们确实每小时都会看到流量高峰。手动选择一个“随机”的时间来运行 cron 作业,或者更好的做法(如果可能的话)是使其在一个真正随机的时间表上运行。
- 在所有请求中发送 User-Agent 标头,包括电子邮件、Twitter 或其他某种形式的联系方式,这样我们就可以在您使用 API 方面遇到问题时联系您。如果不这样做,我们别无选择,只能阻止 IP 地址,而我们更愿意避免这样做。
- 如果您并行发送请求,请做一个好公民,并且最多进行 10 个并发请求,如果您只获取静态文件,则最多 20 个。大量请求的突发可能会对其他常规用户造成问题,所以请尽量分散负载。
- 使用支持 HTTP/2 的客户端,并确保您已启用它,它比每次请求都重新连接要高效得多。
列出包名
所有包
GET https://packagist.org.cn/packages/list.json
{
"packageNames": [
"[vendor]/[package]",
...
]
}
工作示例: https://packagist.org.cn/packages/list.json
按组织列出包
GET https://packagist.org.cn/packages/list.json?vendor=[vendor]
{
"packageNames": [
"[vendor]/[package]",
...
]
}
工作示例: https://packagist.org.cn/packages/list.json?vendor=composer
按类型列出包
GET https://packagist.org.cn/packages/list.json?type=[type]
{
"packageNames": [
"[vendor]/[package]",
...
]
}
工作示例: https://packagist.org.cn/packages/list.json?type=composer-plugin
如果名称不足以检索附加数据
如果您需要的不仅仅是包名,还可以额外请求返回每个包的一个或多个字段。目前支持的字段是: repository
、type
和 abandoned
。
请注意,在请求字段时,响应结构不同。
GET https://packagist.org.cn/packages/list.json?vendor=[type]&fields[]=type&fields[]=repository&fields[]=abandoned
{
"package": {
"[vendor]/[package]": {
"type": "library",
"repository": "https://...",
"abandoned": false|true|string (with advised replacement)
},
...
}
}
工作示例: https://packagist.org.cn/packages/list.json?vendor=composer&fields[]=repository&fields[]=type
列出热门包
如果您需要检索最受欢迎的包(这是按上周的下载量排序的,而不是总下载量,以确保我们降低过去受欢迎的包的排名),请使用此端点以避免为我们的 300K+ 个包分别请求下载统计。这还包括点赞数(github 星标 + packagist.org 收藏)和下载次数。如果需要超过 100 个,API 会分页。
GET https://packagist.org.cn/explore/popular.json?per_page=100
{
"packages": [
{
"name": "[vendor]/[package]",
"description": "[description]",
"url": "https://packagist.org.cn/packages/[vendor]/[package]",
"downloads": 123456,
"favers": 123
},
...
],
"total": 123456,
"next": "https://packagist.org.cn/explore/popular.json?page=2&per_page=100"
}
工作示例: https://packagist.org.cn/explore/popular.json?per_page=100
搜索包
搜索结果分页,您可以通过使用 per_page 参数来更改分页步骤。例如 https://packagist.org.cn/search.json?q=[query]&per_page=5
按名称搜索包
GET https://packagist.org.cn/search.json?q=[query]
{
"results" : [
{
"name": "[vendor]/[package]",
"description": "[description]",
"url": "https://packagist.org.cn/packages/[vendor]/[package]",
"repository": [repository url],
"downloads": [number of downloads],
"favers": [number of favers]
},
...
],
"total": [number of results],
"next": "https://packagist.org.cn/search.json?q=[query]&page=[next page number]"
}
工作示例: https://packagist.org.cn/search.json?q=monolog
按标签搜索包
GET https://packagist.org.cn/search.json?tags=[tag]
{
"results": [
{
"name": "[vendor]/[package]",
"description": "[description]",
"url": "https://packagist.org.cn/packages/[vendor]/[package]",
"repository": "[repository url]",
"downloads": [number of downloads],
"favers": [number of favers]
}
...
],
"total": [numbers of results]
}
工作示例: https://packagist.org.cn/search.json?q=monolog&tags=psr-3
按类型搜索包
GET https://packagist.org.cn/search.json?q=[query]&type=symfony-bundle
{
"results" : [
{
"name": "[vendor]/[package]",
"description": "[description]",
"url": "https://packagist.org.cn/packages/[vendor]/[package]",
"repository": [repository url],
"downloads": [number of downloads],
"favers": [number of favers]
},
...
],
"total": [number of results],
"next": "https://packagist.org.cn/search.json?q=[query]&page=[next page number]"
}
工作示例: https://packagist.org.cn/search.json?q=monolog&type=symfony-bundle
获取包数据
使用 Composer v2 元数据
这是访问数据的首选方式,因为它总是最新的,并且已导出到静态文件中,因此在我们的端点非常高效。
您还可以发送If-Modified-Since
头部来限制您的带宽使用,并根据我们的Last-Modified
头部设置正确的filemtime,在您的端缓存文件。
尽管如此,使用此方法也有一些需要注意的地方。
- 它只提供您包的元数据,但不包括维护者信息、下载统计或github信息。
- 它以压缩格式存在以提高效率,这需要您使用来自composer/metadata-minifier包的
Composer\MetadataMinifier\MetadataMinifier::expand($response['packages'][$packageName])
来恢复完整数据。 p2/$vendor/$package.json
文件只包含标记的版本。如果您想获取关于分支(即开发版本)的信息,您需要下载p2/$vendor/$package~dev.json
。
GET https://repo.packagist.org/p2/[vendor]/[package].json
{
"packages": {
"[vendor]/[package]": [
{
"name": "[vendor]/[package],
"description": [description],
"version": "[version1]",
// ...
},
{
"version": "[version2]",
// ...
}
// ...
]
},
"minified": "composer/2.0"
}
工作示例
- 对于标记的版本:
https://repo.packagist.org/p2/monolog/monolog.json
- 对于开发版本:
https://repo.packagist.org/p2/monolog/monolog~dev.json
想保持最新并知道包何时更新?请查看跟踪包更新API。
使用Composer v1元数据(已弃用)
您还可以发送If-Modified-Since
头部来限制您的带宽使用,并根据我们的Last-Modified
头部设置正确的filemtime,在您的端缓存文件。
尽管如此,使用此方法也有一些需要注意的地方。
- 它只提供您包的元数据,但不包括维护者信息、下载统计或github信息。
- 它包含提供者信息,这些信息必须忽略,但一开始可能会让人困惑。但这将在未来消失。
- 由于v1元数据的弃用,它并不提供所有包。查看公告以获取详细信息。
GET https://repo.packagist.org/p/[vendor]/[package].json
{
"packages": {
"[vendor]/[package]": {
"[version1]": {
"name": "[vendor]/[package],
"description": [description],
// ...
},
"[version2]": {
// ...
}
// ...
}
}
}
工作示例:https://repo.packagist.org/p/monolog/monolog.json
使用API
包的JSON API提供了我们所有的信息,包括下载、依赖项数量、github信息等。然而,它是动态生成的,因此出于性能考虑,我们缓存响应12小时。因此,如果上述静态文件端点足以满足您的需求,请使用它。
GET https://packagist.org.cn/packages/[vendor]/[package].json
{
"package": {
"name": "[vendor]/[package],
"description": [description],
"time": [packagist package creation datetime],
"maintainers": [list of maintainers],
"versions": [list of versions and their dependencies, the same data of composer.json]
"type": [package type],
"repository": [repository url],
"downloads": {
"total": [numbers of download],
"monthly": [numbers of download per month],
"daily": [numbers of download per day]
},
"favers": [number of favers]
}
}
获取包下载统计
如果您需要完整的包信息并且已经使用JSON API,请使用响应中的downloads
键来检索统计数据。
但是,如果您只对一组包名的下载统计数据感兴趣,您可以使用包含总体下载统计数据和收藏数量(github星标 + packagist.org收藏)的统计端点。
GET https://packagist.org.cn/packages/[vendor]/[package]/stats.json
{
"downloads": {
"total": 100,
"monthly": 10,
"daily": 1
},
"versions": [
"[list of versions]",
"[list of versions]"
],
"date": "2022-09-15" # stats collection start date
}
跟踪包更新
此端点为您提供了元数据变更的feed,您可以轮询以了解哪些包需要更新。
首先,您可以轮询API而不带时间戳以获取最新的时间戳,或者通过使用10000 * time()
来创建自己的时间戳。
GET https://packagist.org.cn/metadata/changes.json
{
"error": "Invalid or missing "since" query parameter, make sure you store the timestamp at the initial point you started mirroring, then send that to begin receiving changes, e.g. https://packagist.org.cn/metadata/changes.json?since=16142636710498 for example.",
"timestamp": 16142636710498
}
工作示例:https://packagist.org.cn/metadata/changes.json
之后,您应该存储下一次调用API时的时间戳,例如,如果您10分钟后想了解有什么变化,您再次调用此API,但这次您传递之前的戳记。
GET https://packagist.org.cn/metadata/changes.json?since=16142636710498
{
"actions": [
{
"type": "update",
"package": "acme/package",
"time": 1614264954
},
{
"type": "update",
"package": "foo/bar~dev",
"time": 1614264951
},
{
"type": "delete",
"package": "acme/gone",
"time": 1614264953
}
]
}
工作示例:https://packagist.org.cn/metadata/changes.json?since=17270103700000
在上面的示例中,您收到了3个变更,让我们来看看它们的意义以及您应该做什么来同步这些变更。
acme/update
被更新了(acme/update
的标记版本),您可以获取https://repo.packagist.org/p2/acme/update.json
并确保Last-Modified
至少等于time
值。如果它比这更旧,请等待几秒钟然后重试。由于内部镜像延迟,您可能会遇到竞争条件并得到过时的文件。foo/bar~dev
已更新(foo/bar
的开发版本,您可以通过https://repo.packagist.org/p2/foo/bar~dev.json
获取,并确保Last-Modified
的值至少等于time
的值。acme/gone
已被删除,您也应在您的端将其删除,这意味着acme/gone
和acme/gone~dev
都已被删除。
警告:我们的端上的更改日志最多保留24小时,因此请确保您每天至少调用API一次,否则您可能会收到如下重同步响应
GET https://packagist.org.cn/metadata/changes.json?since=16140636710498
{
"actions": [
{
"type": "resync",
"package": "*",
"time": 1614264954
}
]
}
如果您收到这个响应,应该假设您的数据已过时,您应该重新验证所有内容(如果您使用 Last-Modified
头部缓存了文件,您仍然可以保留这些文件,并确保使用 If-Modified-Since
请求对每个文件进行检查,以确保它们仍然是最新的)。
获取统计
此端点提供了基本的统计信息。
GET https://packagist.org.cn/statistics.json
{
"totals": {
"downloads": [numbers of download]
}
}
列出安全警报
此端点提供安全警告列表。需要传递包列表作为查询或请求参数,或者作为 updatedSince
查询参数的时间戳。
当使用包列表进行查询时,如果已知包没有任何列出漏洞,则将包含在响应中,并且对应的数组为空。如果包名称未列出任何已知漏洞,则根本不会包含在显示中,以表明我们无法获取这些数据。
GET https://packagist.org.cn/api/security-advisories/?updatedSince=[timestamp]&packages[]=[vendor/package]
{
"advisories": {
"[vendor]/[package]": [
{
"advisoryId": "[unique id]",
"packageName": "[vendor]/[package]",
"remoteId": "[deprecated, use sources instead]",
"title": "[title]",
"link": "[url to issue disclosure]",
"cve": "[cve if available]",
"affectedVersions": [affected version in form of a composer constraint]",
"source": "[deprecated, use sources instead]",
"sources": [
{
"name": "[Name of the source where the advisory was found e.g. GitHub or FriendsOfPHP/security-advisories]"
"remoteId": "[A reference to identify the advisory in the source e.g. the GitHub advisory id]"
}
],
"reportedAt": "[date the issue was reported]",
"composerRepository": "[composer repository the package can be found in]",
"severity": [severity if available, following the CVSS3 spec]
}
]
}
}
工作示例: https://packagist.org.cn/api/security-advisories/?packages[]=monolog/monolog
创建包
此端点用于为特定仓库创建包。需要 username
和 apiToken
参数。只允许 POST
方法。需要 content-type: application/json
头部。
此端点被视为不安全,需要使用您的主 API令牌。
POST https://packagist.org.cn/api/create-package?username=[username]&apiToken=[apiToken] {"repository":"[url]"}
{
"status": "success"
}
工作示例
curl -X POST -H'Content-Type:application/json' 'https://packagist.org.cn/api/create-package?username=USERNAME&apiToken=********' -d '{"repository":"https://github.com/Seldaek/monolog"}'
编辑包
此端点允许您编辑包URL。需要 username
和 apiToken
参数。只允许 PUT
方法。需要 content-type: application/json
头部。
此端点被视为不安全,需要使用您的主 API令牌。
PUT https://packagist.org.cn/api/packages/[package name]?username=[username]&apiToken=[apiToken] {"repository":"[url]"}
{
"status": "success"
}
工作示例
curl -X POST -H'Content-Type:application/json' 'https://packagist.org.cn/api/packages/monolog/monolog?username=USERNAME&apiToken=********' -d '{"repository":"https://github.com/Seldaek/monolog"}'
更新包
此端点通过规范仓库URL或packagist.org包URL更新包。需要 username
和 apiToken
参数。只允许 POST
方法。需要 content-type: application/json
头部。
此端点被视为安全,允许使用您的主或安全 API令牌。
POST https://packagist.org.cn/api/update-package?username=[username]&apiToken=[apiToken] {"repository":"[url]"}
{
"status": "success",
"jobs": ["job-id", ".."]
}
工作示例
curl -X POST -H'Content-Type:application/json' 'https://packagist.org.cn/api/update-package?username=USERNAME&apiToken=********' -d '{"repository":"https://github.com/Seldaek/monolog"}'
curl -X POST -H'Content-Type:application/json' 'https://packagist.org.cn/api/update-package?username=USERNAME&apiToken=********' -d '{"repository":"https://packagist.org.cn/monolog/monolog"}'