{"id":18353218,"url":"https://github.com/daodao97/apidog","last_synced_at":"2025-04-05T04:11:44.043Z","repository":{"id":35092504,"uuid":"205554663","full_name":"daodao97/apidog","owner":"daodao97","description":"Api Watch Dog, Hyperf 框架的 Api参数校验 和 swagger 生成组件","archived":false,"fork":false,"pushed_at":"2023-01-29T06:43:25.000Z","size":689,"stargazers_count":151,"open_issues_count":9,"forks_count":29,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-23T22:09:54.412Z","etag":null,"topics":["hyperf","php","swagger","swoole"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daodao97.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-31T14:27:28.000Z","updated_at":"2024-02-15T06:11:42.000Z","dependencies_parsed_at":"2023-02-12T05:17:28.760Z","dependency_job_id":null,"html_url":"https://github.com/daodao97/apidog","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daodao97%2Fapidog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daodao97%2Fapidog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daodao97%2Fapidog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daodao97%2Fapidog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daodao97","download_url":"https://codeload.github.com/daodao97/apidog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284950,"owners_count":20913704,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hyperf","php","swagger","swoole"],"created_at":"2024-11-05T21:38:54.336Z","updated_at":"2025-04-05T04:11:44.025Z","avatar_url":"https://github.com/daodao97.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Api Watch Dog\n一个 [Hyperf](https://github.com/hyperf/hyperf) 框架的 Api 参数校验及 swagger 文档生成组件\n\n1.  根据注解自动进行Api参数的校验, 业务代码更纯粹.\n2.  根据注解自动生成Swagger文档, 让接口文档维护更省心.\n\n\u003e 在 1.2 版本后, 本扩展移除了内部自定义的验证器, 只保留的 hyperf 原生验证器, 以保持验证规则的统一\n\n旧版本文档 [查看](./README_OLD.md)\n\n## 安装\n\n```\ncomposer require daodao97/apidog\n```\n## 使用\n\n#### 1. 发布配置文件\n\n```bash\nphp bin/hyperf.php vendor:publish daodao97/apidog\n\n# hyperf/validation 的依赖发布\n\nphp bin/hyperf.php vendor:publish hyperf/translation\n\nphp bin/hyperf.php vendor:publish hyperf/validation\n```\n\n### 2. 修改配置文件\n\n\u003e 注意 与1.2及之前的版本相比, 配置文件结构及文件名 略有不同\n\u003e \n\u003e (1) 配置文件结构的优化, 增加了swagger外的整体配置\n\u003e\n\u003e (2) 配置文件的名称 由 swagger.php 改为 apidog.php\n\n根据需求修改 `config/autoload/apidog.php`\n\n```php\n\u003c?php\n\nreturn [\n    // enable false 将不会生成 swagger 文件\n    'enable' =\u003e env('APP_ENV') !== 'production',\n    // swagger 配置的输出文件\n    // 当你有多个 http server 时, 可以在输出文件的名称中增加 {server} 字面变量\n    // 比如 /public/swagger/swagger_{server}.json\n    'output_file' =\u003e BASE_PATH . '/public/swagger/swagger.json',\n    // 忽略的hook, 非必须 用于忽略符合条件的接口, 将不会输出到上定义的文件中\n    'ignore' =\u003e function ($controller, $action) {\n        return false;\n    },\n    // 自定义验证器错误码、错误描述字段\n    'error_code' =\u003e 400,\n    'http_status_code' =\u003e 400,\n    'field_error_code' =\u003e 'code',\n    'field_error_message' =\u003e 'message',\n    'exception_enable' =\u003e false,\n    // swagger 的基础配置\n    'swagger' =\u003e [\n        'swagger' =\u003e '2.0',\n        'info' =\u003e [\n            'description' =\u003e 'hyperf swagger api desc',\n            'version' =\u003e '1.0.0',\n            'title' =\u003e 'HYPERF API DOC',\n        ],\n        'host' =\u003e 'apidog.cc',\n        'schemes' =\u003e ['http'],\n    ],\n    'templates' =\u003e [\n    // {template} 字面变量  替换 schema 内容\n    // // 默认 成功 返回\n    // 'success' =\u003e [\n    //     \"code|code\"    =\u003e '0',\n    //     \"result\"  =\u003e '{template}',\n    //     \"message|message\" =\u003e 'Success',\n    // ],\n    // // 分页\n    // 'page' =\u003e [\n    //     \"code|code\"    =\u003e '0',\n    //     \"result\"  =\u003e [\n    //         'pageSize' =\u003e 10,\n    //         'total' =\u003e 1,\n    //         'totalPage' =\u003e 1,\n    //         'list' =\u003e '{template}'\n    //     ],\n    //     \"message|message\" =\u003e 'Success',\n    //],\n    ],\n    // golbal 节点 为全局性的 参数配置\n    // 跟注解相同, 支持 header, path, query, body, formData\n    // 子项为具体定义\n    // 模式一: [ key =\u003e rule ]\n    // 模式二: [ [key, rule, defautl, description] ]\n    'global' =\u003e [\n        // 'header' =\u003e [\n        //     \"x-token|验签\" =\u003e \"required|cb_token\"\n        // ],\n        // 'query' =\u003e [\n        //     [\n        //         'key' =\u003e 'xx|cc',\n        //         'rule' =\u003e 'required',\n        //         'default' =\u003e 'abc',\n        //         'description' =\u003e 'description'\n        //     ]\n        // ]\n    ]\n];\n```\n\n### 3. 启用 Api参数校验中间件\n\n```php\n// config/autoload/middlewares.php\n\nHyperf\\Apidog\\Middleware\\ApiValidationMiddleware::class\n```\n\n### 4. 校验规则的定义\n\n规则列表参见 [hyperf/validation 文档](https://hyperf.wiki/#/zh-cn/validation?id=%e9%aa%8c%e8%af%81%e8%a7%84%e5%88%99)\n\n更详细的规则支持列表可以参考 [laravel/validation 文档](https://learnku.com/docs/laravel/6.x/validation/5144#c58a91)\n\n扩展在原生的基础上进行了封装, 支持方便的进行 `自定义校验` 和 `控制器回调校验`\n\n## 实现思路\n\napi参数的自动校验: 通过中间件拦截 http 请求, 根据注解中的参数定义, 通过 `valiation` 自动验证和过滤, 如果验证失败, 则拦截请求. 其中`valiation` 包含 规则校验, 参数过滤, 自定义校验 三部分. \n\nswagger文档生成: 在`php bin/hyperf.php start` 启动 `http-server` 时, 通过监听 `BootAppConfListener` 事件, 扫码控制器注解, 通过注解中的 访问类型, 参数格式, 返回类型 等, 自动组装 `swagger.json` 结构, 最后输出到 `config/autoload/apidog.php` 定义的文件路径中\n\n## 支持的注解 \n\n#### Api类型\n`GetApi`, `PostApi`, `PutApi`, `DeleteApi`\n\n### 参数类型\n`Header`, `Query`, `Body`, `FormData`, `Path`\n\n### 其他\n`ApiController`, `ApiResponse`, `ApiVersion`, `ApiServer`, `ApiDefinitions`, `ApiDefinition`\n\n```php\n/**\n * @ApiVersion(version=\"v1\")\n * @ApiServer(name=\"http\")\n */\nclass UserController {} \n```\n\n`ApiServer` 当你在 `config/autoload.php/server.php servers` 中配置了多个 `http` 服务时, 如果想不同服务生成不同的`swagger.json` 可以在控制器中增加此注解.\n\n`ApiVersion` 当你的统一个接口存在不同版本时, 可以使用此注解, 路由注册时会为每个木有增加版本号, 如上方代码注册的实际路由为 `/v1/user/***`\n\n`ApiDefinition` 定义一个 `Definition`，用于Response的复用。 *swagger* 的difinition是以引用的方式来嵌套的，如果需要嵌套另外一个(值为object类型就需要嵌套了)，可以指定具体 `properties` 中的 `$ref` 属性\n\n`ApiDefinitions` 定义一个组`Definition`\n\n`ApiResponse` 响应体的`schema`支持为key设置简介. `$ref` 属性可以引用 `ApiDefinition` 定义好的结构(该属性优先级最高)\n```php\n@ApiResponse(code=\"0\", description=\"删除成功\", schema={\"id|这里是ID\":1})\n@ApiResponse(code=\"0\", description=\"删除成功\", schema={\"$ref\": \"ExampleResponse\"})\n```\n\n具体使用方式参见下方样例\n\n## 样例\n\n```php\n\u003c?php\ndeclare(strict_types=1);\nnamespace App\\Controller;\n\nuse Hyperf\\Apidog\\Annotation\\ApiController;\nuse Hyperf\\Apidog\\Annotation\\ApiResponse;\nuse Hyperf\\Apidog\\Annotation\\ApiVersion;\nuse Hyperf\\Apidog\\Annotation\\Body;\nuse Hyperf\\Apidog\\Annotation\\DeleteApi;\nuse Hyperf\\Apidog\\Annotation\\FormData;\nuse Hyperf\\Apidog\\Annotation\\GetApi;\nuse Hyperf\\Apidog\\Annotation\\Header;\nuse Hyperf\\Apidog\\Annotation\\PostApi;\nuse Hyperf\\Apidog\\Annotation\\Query;\nuse Hyperf\\HttpServer\\Contract\\RequestInterface;\nuse Hyperf\\Utils\\ApplicationContext;\n\n/**\n * @ApiVersion(version=\"v1\")\n * @ApiController(tag=\"demo管理\", description=\"demo的新增/修改/删除接口\")\n * @ApiDefinitions({\n *  @ApiDefinition(name=\"DemoOkResponse\", properties={\n *     \"code|响应码\": 200,\n *     \"msg|响应信息\": \"ok\",\n *     \"data|响应数据\": {\"$ref\": \"DemoInfoData\"}\n *  }),\n *  @ApiDefinition(name=\"DemoInfoData\", properties={\n *     \"userInfo|用户数据\": {\"$ref\": \"DemoInfoDetail\"}\n *  }),\n *  @ApiDefinition(name=\"DemoInfoDetail\", properties={\n *     \"id|用户ID\": 1,\n *     \"mobile|用户手机号\": { \"default\": \"13545321231\", \"type\": \"string\" },\n *     \"nickname|用户昵称\": \"nickname\",\n *     \"avatar\": { \"default\": \"avatar\", \"type\": \"string\", \"description\": \"用户头像\" },\n *  })\n * })\n */\nclass DemoController extends AuthController\n{\n\n    /**\n     * @PostApi(path=\"/demo\", description=\"添加一个用户\")\n     * @Header(key=\"token|接口访问凭证\", rule=\"required\")\n     * @FormData(key=\"a.name|名称\", rule=\"required|max:10|cb_checkName\")\n     * @FormData(key=\"a.sex|年龄\", rule=\"integer|in:0,1\")\n     * @FormData(key=\"aa|aa\", rule=\"required|array\")\n     * @FormData(key=\"file|文件\", rule=\"file\")\n     * @ApiResponse(code=\"-1\", description=\"参数错误\", template=\"page\")\n     * @ApiResponse(code=\"0\", description=\"请求成功\", schema={\"id\":\"1\"})\n     */\n    public function add()\n    {\n        return [\n            'code'   =\u003e 0,\n            'id'     =\u003e 1,\n            'params' =\u003e $this-\u003erequest-\u003epost(),\n        ];\n    }\n\n    // 自定义的校验方法 rule 中 cb_*** 方式调用\n    public function checkName($attribute, $value)\n    {\n        if ($value === 'a') {\n            return \"拒绝添加 \" . $value;\n        }\n\n        return true;\n    }\n\n    /**\n     * 请注意 body 类型 rules 为数组类型\n     * @DeleteApi(path=\"/demo\", description=\"删除用户\")\n     * @Body(rules={\n     *     \"id|用户id\":\"required|integer|max:10\",\n     *     \"deepAssoc|深层关联\":{\n     *        \"name_1|名称\": \"required|integer|max:20\"\n     *     },\n     *     \"deepUassoc|深层索引\":{{\n     *         \"name_2|名称\": \"required|integer|max:20\"\n     *     }},\n     *     \"a.b.c.*.e|aa\":\"required|integer|max:10\",\n     * })\n     * @ApiResponse(code=\"-1\", description=\"参数错误\")\n     * @ApiResponse(code=\"0\", description=\"删除成功\", schema={\"id\":1})\n     */\n    public function delete()\n    {\n        $body = $this-\u003erequest-\u003egetBody()-\u003egetContents();\n        return [\n            'code'  =\u003e 0,\n            'query' =\u003e $this-\u003erequest-\u003egetQueryParams(),\n            'body'  =\u003e json_decode($body, true),\n        ];\n    }\n\n    /**\n     * @GetApi(path=\"/demo\", description=\"获取用户详情\")\n     * @Query(key=\"id\", rule=\"required|integer|max:0\")\n     * @ApiResponse(code=\"-1\", description=\"参数错误\")\n     * @ApiResponse(code=\"0\", schema={\"id\":1,\"name\":\"张三\",\"age\":1}, template=\"success\")\n     */\n    public function get()\n    {\n        return [\n            'code' =\u003e 0,\n            'id'   =\u003e 1,\n            'name' =\u003e '张三',\n            'age'  =\u003e 1,\n        ];\n    }\n\n    /**\n     * schema中可以指定$ref属性引用定义好的definition\n     * @GetApi(path=\"/demo/info\", description=\"获取用户详情\")\n     * @Query(key=\"id\", rule=\"required|integer|max:0\")\n     * @ApiResponse(code=\"-1\", description=\"参数错误\")\n     * @ApiResponse(code=\"0\", schema={\"$ref\": \"DemoOkResponse\"})\n     */\n    public function info()\n    {\n        return [\n            'code' =\u003e 0,\n            'id'   =\u003e 1,\n            'name' =\u003e '张三',\n            'age'  =\u003e 1,\n        ];\n    }\n\n    /**\n     * @GetApi(path=\"/demos\", summary=\"用户列表\")\n     * @ApiResponse(code=\"200\", description=\"ok\", schema={{\n     *     \"a|aa\": {{\n     *          \"a|aaa\":\"b\",\"c|ccc\":5.2\n     *      }},\n     *     \"b|ids\": {1,2,3},\n     *     \"c|strings\": {\"a\",\"b\",\"c\"},\n     *     \"d|dd\": {\"a\":\"b\",\"c\":\"d\"},\n     *     \"e|ee\": \"f\"\n     * }})\n     */\n    public function list()\n    {\n        return [\n            [\n                \"a\" =\u003e [\n                    [\"a\" =\u003e \"b\", \"c\" =\u003e \"d\"],\n                ],\n                \"b\" =\u003e [1, 2, 3],\n                \"c\" =\u003e [\"a\", \"b\", \"c\"],\n                \"d\" =\u003e [\n                    \"a\" =\u003e \"b\",\n                    \"c\" =\u003e \"d\",\n                ],\n                \"e\" =\u003e \"f\",\n            ],\n        ];\n    }\n\n}\n```\n\n## Swagger UI启动\n\n本组件提供了两种方式来启用`SwaggerUI`\n, 当`config/autoload/apidog.php enable = true` 时\n\n#### 方式一 \n\n系统启动时, `swagger.json` 会自动输出到配置文件中定义的 `output_file`中, 此时我们到`swagger ui`的前端文件结合`nginx`启动web服务\n\n#### 方式二\n\n也可以使用组件提供的快捷命令, 快速启动一个 `swagger ui`.\n\n```bash\nphp bin/hyperf.php apidog:ui\n\nphp bin/hyperf.php apidog:ui --port 8888\n```\n\n![hMvJnQ](https://gitee.com/daodao97/asset/raw/master/imgs/hMvJnQ.jpg)\n\n## Swagger展示\n\n![AOFVzI](https://gitee.com/daodao97/asset/raw/master/imgs/AOFVzI.jpg)\n\n## 更新日志\n- 20220222\n  - swagger bug fix by [PR](https://github.com/daodao97/apidog/pull/67)   \n- 20210829\n  - fix `swagger` 生成时 `server` 类型过滤问题, 屏蔽非http的服务\n  - 增加 `global` 全局的参数规则, 详见 `apidog.php` `global` 节点\n- 20201230\n  - 支持 hyperf 2.1 版本\n  - 修复 `@Header` 参数名被底层转换为全小写导致的验证无效\n- 20201126 \n  - 统一 `version`, `prefix`, `path` 的前缀处理逻辑 [issue/42](https://github.com/daodao97/apidog/issues/42)\n- 20201111 [@ice](https://github.com/ice-leng)\n  - 修复 初始化 swagger.json  文件生成\n  - 修复 definition 在swagger ui 正确显示 定义数据类型\n  - 添加 注解 Header ，Query 支持 类 注解\n  - 添加 FormData 注解 key 参数 支持 a.b 验证 swagger ui 支持\n  - 添加 Body 注解 支持 参数 a.b  和 a.*.b 验证 swagger ui 支持\n  - 修复 definition 返回 参数为 小数在 swagger ui 不显示问题\n  - 添加 异常 ApiDogException 抛出，以及配置 异常抛出开关\n  - 添加 返回数据 模版 \n- 20201014\n    - 优化swagger ui, 命令模式监听`0.0.0.0`, 并支持自定义端口\n- 20200911\n    - Response 增加纯列表模式 [@zxyfaxcn](https://github.com/zxyfaxcn)\n- 20200904\n    - 增加 `ApiDefinitions` 与 `ApiDefinition` 注解，可用于相同Response结构体复用 [@jobinli](https://github.com/jobinli)\n    - `ApiResponse schema` 增加 `$ref` 属性，用于指定由 `ApiDefinition` 定义的结构体 [@jobinli](https://github.com/jobinli)\n- 20200813\n    - 增加Api版本, `ApiVersion`, 可以给路由增加版本前缀\n    - 增加多服务支持, `ApiServer`, 可以按服务生成`swagger.json`\n    - `ApiResponse shema` 支持字段简介\n- 20200812\n    - `body` 结构增加多级支持\n    - `FormData` 增加 文件上传样例\n    - 增加`swagger ui`命令行工具\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaodao97%2Fapidog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaodao97%2Fapidog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaodao97%2Fapidog/lists"}