生成接口文档
easyswoole/http-annotation 4.x 可以扫描带 #[ApiGroup] 的注解控制器和带 #[Api] 的公开方法,生成完整 HTML。可以用脚本生成静态文件,也可以在控制器里直接响应,例如访问 /doc。两种方式都使用 Document::scan2html(),区别是生成时机。
先准备可扫描的控制器
至少完成安装与继承或控制器组与接口定义中的示例。扫描时控制器文件必须能被应用的 Composer 自动加载:类名、命名空间、文件路径要一致。组件只把有 #[ApiGroup] 的注解控制器放进文档;只有带 #[Api] 的公开方法会显示为接口。
创建生成脚本
在应用项目根目录新建 build-api-doc.php:
<?php
require __DIR__ . '/vendor/autoload.php';
use EasySwoole\HttpAnnotation\Document\Document;
$document = new Document(
__DIR__ . '/App/HttpController',
'App\\HttpController'
);
$document->getConfig()->setProjectName('我的 API');
$document->getConfig()->setHost('http://127.0.0.1:9501');
$html = $document->scan2html();
$output = __DIR__ . '/Static/api.html';
if (file_put_contents($output, $html) === false) {
throw new RuntimeException("无法写入 {$output}");
}
echo "已生成 {$output}\n";
Document 的第一个参数是控制器实际目录,第二个参数是该目录对应的根命名空间。scan2html() 返回 HTML 字符串,不会自动保存文件;脚本把它写入 Static/api.html。先确保应用项目中有 Static 目录,然后运行:
mkdir -p Static
php build-api-doc.php
php -S 127.0.0.1:8080 -t Static
另开浏览器访问 http://127.0.0.1:8080/api.html。这里的 php -S 只用来本地预览静态文档;业务 API 仍由 9501 端口的 EasySwoole 服务处理。若项目已经开启 document_root => EASYSWOOLE_ROOT . '/Static' 和 enable_static_handler => true,也可按项目静态资源规则直接由框架提供该文件。
在控制器中直接响应 /doc
如果希望打开一个固定地址就看到最新接口文档,可在应用项目根目录新建 App/HttpController/ApiDoc.php:
<?php
namespace App\HttpController;
use EasySwoole\Http\AbstractInterface\Controller;
use EasySwoole\HttpAnnotation\Document\Document;
class ApiDoc extends Controller
{
public function index(): void
{
$document = new Document(
EASYSWOOLE_ROOT . '/App/HttpController',
'App\\HttpController'
);
$document->getConfig()->setProjectName('我的 API');
$document->getConfig()->setHost('http://127.0.0.1:9501');
$this->response()->withHeader('Content-Type', 'text/html; charset=utf-8');
$this->response()->write($document->scan2html());
}
}
这里使用普通 Controller,因为文档页面本身不是需要加入接口文档的 API。EASYSWOOLE_ROOT 指向项目根目录,避免服务部署后依赖当前工作目录。
然后在现有 App/HttpController/Router.php 的 initialize() 中增加一条路由,保留文件里原有路由和 setPathInfoMode() 设置:
$routeCollector->get('/doc', '/ApiDoc/index');
重载服务后打开 http://127.0.0.1:9501/doc。也可以执行:
php easyswoole.php server reload
curl -i http://127.0.0.1:9501/doc
此方案每次请求 /doc 都会扫描控制器并生成 HTML,适合开发环境或接口数量较少的项目。接口较多或访问频繁时,优先使用上面的脚本生成静态文件,或自行加入缓存并在代码变更后刷新。接口文档可能包含内部地址、参数和请求示例;生产环境开放 /doc 前应增加鉴权或仅允许内网访问。
分组、路径与说明如何出现在文档中
例如 #[ApiGroup(groupName: 'Catalog.Product')] 会形成 Catalog → Product 导航;其 Product::index() 和 Product::create() 只有在方法上写了 #[Api] 才会被扫描。分组名不能重复。组件按控制器类和 Action 名构建默认文档路径,不会读取你在 Router 中自定义的所有 URL;若实际项目用 /api/products 等别名,需要核对文档展示路径,不能误以为注解会自动注册路由。
Api 支持 description、requestParam、请求/响应示例及 deprecated 标记。可在接口上增加响应样例:
use EasySwoole\HttpAnnotation\Bean\Example\Array2Json;
#[Api(
allowMethod: HttpMethod::GET,
description: '列出商品',
responseExamples: [
new Array2Json(['code' => 200, 'result' => [['id' => 1]]]),
]
)]
public function index(): void
{
$this->writeJson(200, [['id' => 1]]);
}
这段是对上一章 Product::index() 的替换片段,不是可单独运行的文件。接口文档还提供“立即尝试”,会按声明的请求方法和参数构造浏览器请求。浏览器跨域、Cookie、CORS 仍受普通 Web 安全规则约束;公开生成文件前检查其中的示例数据和说明,不要把密钥或内部地址发布出去。
常见问题
- 扫描结果为空:检查控制器是否继承
AnnotationController、类上是否有#[ApiGroup]、方法上是否有#[Api]、Composer 自动加载是否正确。 - 分组报重复:不同控制器不能使用同一个完整
groupName。 - 修改接口后页面没变化:重新执行
php build-api-doc.php并刷新浏览器;运行服务中的 Attribute 缓存需要重载时再执行php easyswoole.php server reload。 /doc返回 404:确认Router.php增加了get('/doc', '/ApiDoc/index'),并已重载服务;若生成时出错,再检查扫描路径和注解控制器是否能正常加载。- 在线试运行失败:先用 curl 确认接口可用,再检查文档 host、实际路由和浏览器 CORS;生成 HTML 不会自动启动 API 服务。