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

如果名称不足以检索附加数据

如果您需要的不仅仅是包名,还可以额外请求返回每个包的一个或多个字段。目前支持的字段是: repositorytypeabandoned

请注意,在请求字段时,响应结构不同。

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"
}

工作示例

想保持最新并知道包何时更新?请查看跟踪包更新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]
  }
}

工作示例:https://packagist.org.cn/packages/monolog/monolog.json

获取包下载统计

如果您需要完整的包信息并且已经使用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
}

工作示例:https://packagist.org.cn/monolog/monolog/stats.json

跟踪包更新

此端点为您提供了元数据变更的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/goneacme/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]
  }
}

工作示例: https://packagist.org.cn/statistics.json

列出安全警报

此端点提供安全警告列表。需要传递包列表作为查询或请求参数,或者作为 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

创建包

此端点用于为特定仓库创建包。需要 usernameapiToken 参数。只允许 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。需要 usernameapiToken 参数。只允许 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更新包。需要 usernameapiToken 参数。只允许 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"}'