wapmorgan / openapi-generator
从PHP代码(PhpDoc、函数签名和类型提示)和项目(适用于yii2、slim、laravel)直接生成OpenApi配置。可用于维护大型单体后端的大型API文档。
0.4.9
2024-04-19 22:31 UTC
Requires
- php: >=7.4
- doctrine/annotations: ^1.6
- phpdocumentor/reflection-docblock: ^4.3|^5.1
- symfony/console: ^5.0|^6.0
- zircote/swagger-php: ^3.0
README
这是一个与原始源代码 + phpdoc一起工作的OpenApi配置生成器。
此库的主要目的是自动化生成具有许多方法的现有JSON-API的OpenApi规范。想法来自@maxonrock。
OpenApiGenerator
它做什么?
它直接从源代码生成用于您用PHP编写的基于REST JSON的API的OpenApi 3.0规范文件。您不需要手动编写OpenApi规范。
Laravel示例
-
路由
Route::get('/selector/lists', [\App\Http\Controllers\SelectorController::class, 'lists']); Route::post('/selector/select', [\App\Http\Controllers\SelectorController::class, 'select']); Route::get('/selector/goTo', [\App\Http\Controllers\SelectorController::class, 'goTo']); Route::get('/geo/detect', [\App\Http\Controllers\GeoController::class, 'detect']); Route::get('/geo/select', [\App\Http\Controllers\GeoController::class, 'select']);
-
一个控制器
/** * Returns lists of filters * @param Request $request * @return ListsResponse */ public function lists(Request $request) { return new ListsResponse([ // 'persons' => range(1, 15), 'persons' => array_keys(Menu::$personsList), 'tastes' => Menu::$tastes, 'meat' => Menu::$meat, 'pizzas' => Menu::$pizzas, ]); } /** * Makes a selection of pizzas according to criteria * @param \App\Http\Requests\SelectPizzas $request * @return PizzaListItem[] */ public function select(\App\Http\Requests\SelectPizzas $request) { $validated = $request->validated(); return (new Selector())->select( $validated['city'], $validated['persons'], $validated['tastes'] ?? null, $validated['meat'] ?? null, $validated['vegetarian'] ?? false, $validated['maxPrice'] ?? null); }
-
一个请求和两个响应
class SelectPizzas extends FormRequest { public function rules() { // ... return array_merge([ 'city' => ['required', 'string'], 'persons' => ['required', Rule::in(array_keys(Menu::$personsList))], 'vegetarian' => ['boolean'], 'maxPrice' => ['numeric'], 'pizzas' => ['array', Rule::in(array_keys(Menu::$pizzas))], ], $tastes, $meat); } } class ListsResponse extends BaseResponse { /** @var string[] */ public $persons; /** @var string[] */ public $tastes; /** @var string[] */ public $meat; /** @var string[] */ public $pizzas; } class PizzaListItem extends BaseResponse { public string $pizzeria; public string $id; public int $sizeId; public string $name; public float $size; public array $tastes; public array $meat; public float $price; public float $pizzaArea; public float $pizzaCmPrice; public string $thumbnail; public array $ingredients; public int $dough; }
-
从代码生成结果:具有描述和参数的
┌─────────┬─────────────────┬──────────────────────────┐ │ get │ /selector/lists │ Returns lists of filters │ ├─────────┼─────────────────┼──────────────────────────┤ │ Result (4) │ │ persons │ array of string │ │ │ tastes │ array of string │ │ │ meat │ array of string │ │ │ pizzas │ array of string │ │ └─────────┴─────────────────┴──────────────────────────┘ ┌──────────────────┬──────────────────┬───────────────────────────────────────────────────┐ │ post │ /selector/select │ Makes a selection of pizzas according to criteria │ ├──────────────────┼──────────────────┼───────────────────────────────────────────────────┤ │ Parameters (15) │ │ string │ city │ │ │ string │ persons │ │ │ boolean │ vegetarian │ │ │ number │ maxPrice │ │ │ array │ pizzas │ │ │ boolean │ tastes.cheese │ │ │ boolean │ tastes.sausage │ │ │ boolean │ tastes.spicy │ │ │ boolean │ tastes.mushroom │ │ │ boolean │ tastes.exotic │ │ │ boolean │ meat.chicken │ │ │ boolean │ meat.pork │ │ │ boolean │ meat.beef │ │ │ boolean │ meat.fish │ │ │ boolean │ meat.sauce_meat │ │ ├──────────────────┼──────────────────┼───────────────────────────────────────────────────┤ │ Result (14) │ │ │ array of │ │ │ [*].pizzeria │ string │ │ │ [*].id │ string │ │ │ [*].sizeId │ integer │ │ │ [*].name │ string │ │ │ [*].size │ integer │ │ │ [*].tastes │ array of │ │ │ [*].meat │ array of │ │ │ [*].price │ integer │ │ │ [*].pizzaArea │ integer │ │ │ [*].pizzaCmPrice │ integer │ │ │ [*].thumbnail │ string │ │ │ [*].ingredients │ array of │ │ │ [*].dough │ integer │ │ └──────────────────┴──────────────────┴───────────────────────────────────────────────────┘
工作原理
- 爬虫收集有关API的信息(标签、安全模式和服务器、所有端点)并包含生成器的设置。爬虫依赖于框架。
- 生成器通过分析源代码来填充openapi规范,其中包含端点信息
- 操作的摘要和描述
- 参数和操作结果的生成器是通用的。它只是从爬虫接收信息,并按爬虫规则分析代码。
更详细的过程描述请参阅工作原理文档。
如何使用
调用控制台脚本来生成您的项目的openapi(通过集成)
例如,对于yii2项目
- 在项目上运行解析器以分析文件和检索端点信息
./vendor/bin/openapi-generator scrape --scraper yii2 ./ # And more deeper scan ./vendor/bin/openapi-generator generate --scraper yii2 --inspect ./
- 通过
specification_name.yml
将规范生成到api_docs
文件夹中的yaml文件./vendor/bin/openapi-generator generate --scraper yii2 ./ ./api_docs/ # Or with your own scraper (child of one of basic scrapers) ./vendor/bin/openapi-generator generate --scraper components/api/OpenApiScraper.php ./ ./api_docs/
- 使用规范部署swagger(例如,在8091端口上api_docs/main.yml)
docker run -p 8091:8080 --rm -e URL=./apis/main.yaml -v $(pwd):/usr/share/nginx/html/apis/ swaggerapi/swagger-ui:v4.15.2
更详细的描述请参阅使用文档。
集成
有几个集成:Yii2、Laravel、Slim。详细信息请参阅集成文档。您可以为框架或项目编写自己的集成。
扩展
新爬虫
您使用(或扩展)预定义的爬虫(见集成)或从头开始创建自己的爬虫(扩展DefaultScraper
),它应返回包含您的API端点的列表。此外,您的爬虫还应提供标签、安全模式等。
爬虫应返回包含以下内容的规范列表(例如,API版本的列表):
- meta - 规范的版本/描述/外部文档。
- servers - 服务器列表(基本URL)。
- tags - 标签列表,包括描述和其他属性(端点的分类)。
- securitySchemes - 安全模式列表(授权类型)。
- endpoints - API端点列表(单独的回调)。
有关爬虫结果的详细信息请参阅另一份文档。
设置
DefaultGenerator提供了一组设置来调整生成器。
用法
$generator->changeSetting(DefaultGenerator::CHANGE_GET_TO_POST_FOR_COMPLEX_PARAMETERS, true);
默认情况下,它们都未启用。
限制
- 仅支持查询参数(
url?param1=...¶m2=...
)或请求体JSON参数({data: 123}
)。 - 仅支持一种响应类型 - HTTP 200响应。
- 不支持参数的
format
、example
以及其他验证器。
待办事项
- 在一个端点上支持少数操作(GET/POST/PUT/DELETE/...)。
- 支持请求体参数(当参数为复杂对象时) - 部分支持。
- 支持少数响应(具有不同的HTTP状态码)。
- 将类类型提取到单独的组件中(到openapi组件)。
- 支持除JSON之外的其他请求/响应类型。
- 添加
@paramFormat
以指定参数格式 - 部分支持。 - 支持动态模型中的动态动作参数。
- 切换到3.0/3.1(https://openapis.org.cn/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0)