API 文档生成

Viswoole 路由系统内置了 API 文档自动生成能力。启用后,框架会解析路由注解中的元信息(标题、描述、参数、返回值),自动构建结构化的接口文档。

启用配置

config/router.php 中开启 API 文档功能:

php
return [
    // ... 其他配置

    'api_doc' => [
        'enable'   => true,   // 启用 API 文档生成
        'header'   => [],      // 全局 Header 参数(数组类型)
        'query'    => [],      // 全局 Query 参数(数组类型)
        'body'     => [],      // 全局 Body 参数(数组类型)
        'returned' => [],      // 全局返回值结构(数组类型)
    ],
];

配置项说明

配置项类型默认值说明
enableboolfalse是否启用 API 文档生成
headerarray[]全局 Header 参数定义(数组类型)
queryarray[]全局 Query 参数定义(数组类型)
bodyarray[]全局 Body 参数定义(数组类型)
returnedarray[]全局返回值结构定义(数组类型)

参数注解

通过自动注入注解声明接口的入参信息,框架会自动解析并纳入文档。这些注解均无构造函数参数,参数名取自 PHP 参数名(不区分大小写)。

自动注入注解

框架提供了便捷的专用注解,用于从不同数据源注入参数:

php
use Viswoole\HttpServer\AutoInject\{InjectGet, InjectPost, InjectHeader, InjectFile};

#[RouteMapping(paths: ['/upload'], method: ['POST'], title: '上传文件')]
public function upload(
    #[InjectHeader] string $authorization,           // 从 Header 注入
    #[InjectGet] string $category,                   // 从 Query 注入
    #[InjectPost] UploadedFile $file,                // 从 Body 注入
    #[InjectFile] UploadedFile $document,            // 从上传文件注入
): array {}

注意:这些注解无构造函数参数,参数名必须与 header/query 字段名一致(不区分大小写)。例如 #[InjectHeader] string $authorization 会从 Authorization 请求头中取值。

Returned 注解

Returned 注解用于声明接口返回值的结构:

php
use Viswoole\Router\ApiDoc\Annotation\Returned;

#[RouteMapping(paths: ['/user/list'], method: ['GET'], title: '用户列表')]
#[Returned(
    title: '成功',
    data: [
        'code' => 200,
        'message' => '成功',
        'data' => [],
    ],
)]
public function list(): array {}

Returned 属性说明

属性类型默认值说明
titlestring(必填)返回值标题
dataarray | string(必填)示例响应数据,自动推导结构
statusCodeint200HTTP 状态码
typestringapplication/json响应内容类型
sortint0排序,数值越大越靠前

提示data 支持传入数组或字符串。传入数组时,框架会自动推导字段类型和嵌套结构;键名支持 name|描述name?|描述 语法标记可选字段。

元信息提取

除显式声明的参数注解外,框架还会从 #[RouteMapping] 中自动提取以下元信息:

php
#[RouteMapping(
    paths: ['/order/create'],
    method: ['POST'],
    title: '创建订单',              // → 文档标题
    description: '提交新订单',       // → 文档描述
)]
public function create(): array {}

自动提取的字段:

来源字段说明
#[RouteMapping]->title标题接口显示名称
#[RouteMapping]->description描述接口详细说明
#[RouteMapping]->method请求方法GET / POST 等
#[RouteMapping]->paths请求路径路径列表
控制器命名空间tags分类标签(自动从命名空间推断)

完整示例

php
<?php
namespace App\Controller\Api\V1;

use Viswoole\HttpServer\AutoInject\{InjectGet, InjectPost, InjectHeader};
use Viswoole\Router\Annotation\{
    Controller,
    RouteMapping,
};
use Viswoole\Router\ApiDoc\Annotation\Returned;

#[Controller(prefix: '/api/v1')]
class UserController
{
    #[RouteMapping(
        paths: ['/user/login'],
        method: ['POST'],
        title: '用户登录',
        description: '通过手机号和验证码登录',
    )]
    #[Returned(
        title: '登录成功,返回 Token',
        data: [
            'code' => 200,
            'data|访问令牌' => [
                'token' => 'string',
                'expires_in|有效期(秒)' => 3600,
            ],
        ],
    )]
    public function login(
        #[InjectPost] string $phone,
        #[InjectPost] string $code,
    ): array
    {
        return AuthService::login($phone, $code);
    }

    #[RouteMapping(
        paths: ['/user/profile'],
        method: ['GET'],
        title: '个人信息',
        description: '获取当前登录用户的详细信息',
    )]
    #[Returned(
        title: '成功返回用户信息',
        data: [
            'code' => 200,
            'data' => [
                'id' => 1,
                'name' => '张三',
                'avatar?' => null,
            ],
        ],
    )]
    public function profile(
        #[InjectHeader] string $authorization,
    ): array
    {
        return AuthService::user($authorization);
    }
}

生成的文档结构大致如下:

json
{
  "paths": {
    "/api/v1/user/login": {
      "post": {
        "summary": "用户登录",
        "description": "通过手机号和验证码登录",
        "tags": ["API", "V1", "User"],
        "parameters": [
          {
            "name": "phone",
            "in": "body",
            "required": true,
            "type": "string",
            "description": "手机号"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "code": { "type": "string", "description": "短信验证码" }
                },
                "required": ["code"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "登录成功,返回 Token",
            "schema": {
              /* ... */
            }
          }
        }
      }
    }
  }
}

最佳实践

  1. 保持注解与签名同步:自动注入注解的参数名应与 header/query 字段语义一致
  2. 必填参数明确标注:通过参数类型(非可空)来声明必填字段
  3. Returned 描述关键字段:使用 name|描述 语法重点标注嵌套结构和可空字段
  4. title 简洁准确:作为文档目录中的显示名称,应一目了然