szhukovwork/openapi-generator

直接从PHP代码(PhpDoc,函数签名和类型提示)和项目(适用于yii2,slim,laravel)生成OpenApi配置。可用于维护大型单体后端的大API文档。

dev-master 2024-02-16 08:55 UTC

This package is auto-updated.

Last update: 2024-09-16 10:06:40 UTC


README

这是一个与原始源代码一起工作的OpenApi配置生成器。

Latest Stable Version Latest Unstable Version License

此库的主要目的是自动生成大量方法的现有JSON-API的OpenApi规范。由@maxonrock提出。

  1. Open Api生成器
  2. 扩展

OpenApiGenerator

它做什么?

它直接从源代码生成针对您用PHP编写的基于REST JSON的API的OpenApi 3.0规范文件。您不需要手动编写OpenApi规范。

Laravel示例

  1. 路由

    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']);
  2. 一个控制器

    /**
    * 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);
    }
  3. 一个请求和两个响应

    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;
    }
  4. 代码生成的结果:两个带有描述和select参数的端点。

    ┌─────────┬─────────────────┬──────────────────────────┐
    │ 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          │                                                   │
    └──────────────────┴──────────────────┴───────────────────────────────────────────────────┘
    

如何工作

  1. 抓取器收集有关API(标签、安全方案和服务器、所有端点)的信息,并包含生成器的设置。抓取器是框架相关的。
  2. 生成器通过分析源代码填充openapi规范,以端点信息。
    • 操作摘要和描述
    • 参数和生成器操作的结果是共同的。它只是从抓取器接收信息,并按照抓取器的规则分析代码。

更详细的过程描述在如何工作文档中。

如何使用

调用控制台脚本来生成项目的OpenApi(使用集成)

例如,对于yii2项目

  1. 在项目上运行解析器以分析文件并检索端点信息
    ./vendor/bin/openapi-generator scrape --scraper yii2 ./
    # And more deeper scan
    ./vendor/bin/openapi-generator generate --scraper yii2 --inspect ./
  2. 通过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/
  3. 部署具有规范的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响应类型。
  • 不支持参数的formatexample和其他验证器。

待办事项

  • 对一个端点支持的操作有限(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