soft-chen/laravel-openapi

根据 Laravel 路由和控制器 结合 DocBlocks 生成 OpenAPI 文档。

Maintainers

Package info

gitee.com/soft-chen/laravel-openapi.git

Homepage

pkg:composer/soft-chen/laravel-openapi

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

0.0.6 2026-04-19 21:21 UTC

This package is not auto-updated.

Last update: 2026-04-20 00:32:45 UTC


README

Latest Version on Packagist Total Downloads

soft-chen/laravel-openapi 用于根据 Laravel 路由和控制器 DocBlock 生成基础 OpenAPI 文档对象。

本包保持轻量:仅注册 LaravelOpenApiServiceProvider 并支持发布 config/openapi.php 配置文件,不包含命令、视图、迁移或门面。

环境要求

  • PHP ^8.2
  • Laravel ^11.0^12.0^13.0

安装

composer require soft-chen/laravel-openapi

Laravel 会通过 Composer 自动发现并注册服务提供者。若项目关闭了包自动发现,可手动注册:

// bootstrap/providers.php
return [
    SoftChen\LaravelOpenApi\Providers\LaravelOpenApiServiceProvider::class,
];

发布配置

本包配置发布 tag 固定为 laravel-openapi-config

php artisan vendor:publish --tag="laravel-openapi-config"

也可以指定 Provider 发布:

php artisan vendor:publish --provider="SoftChen\LaravelOpenApi\Providers\LaravelOpenApiServiceProvider" --tag="laravel-openapi-config"

发布后会生成 config/openapi.php。默认配置示例:

return [
    'default' => [
        'title' => 'API Docs',
        'description' => 'API documentation',
        'version' => '1.0.0',
        'handler' => null,
        'cache_enable' => true,
        'cache' => [
            'ttl' => 86400,
            'store' => null,
        ],
        'needLoginMiddleware' => [
            // 'admin',
        ],
        'openapi' => [
            'openapi' => '3.0.3',
            // 'components' => [
            //     'securitySchemes' => [
            //         'Authorization' => [
            //             'type' => 'apiKey',
            //             'in' => 'header',
            //             'name' => 'Authorization',
            //         ],
            //     ],
            // ],
            // 'security' => [
            //     ['Authorization' => []],
            // ],
        ],
        'route' => [
            'include' => [
                // 'api/*',
                // 'api.*',
            ],
            'exclude' => [
                // '_ignition/*',
            ],
        ],
    ],
];

配置文件第一层 key 是文档分组名。调用生成器时不传分组名会默认使用第一个分组。

生成文档

use SoftChen\LaravelOpenApi\OpenApiGenerator;

$openapi = OpenApiGenerator::generate();

// 指定分组
$adminOpenapi = OpenApiGenerator::generate('default');

返回值是 SoftChen\LaravelOpenApi\OpenApiDocument 对象,内部保存 openapiphp\openapi\spec\OpenApi,可按项目需要读取字段、转换为数组、JSON、写入文件或继续二次处理。

$document = OpenApiGenerator::generate('default');

$title = $document->info->title;
$pathItem = $document->paths['/users'] ?? null;
$operation = $pathItem?->get;
$response = $operation?->responses['200'] ?? null;

$array = $document->toArray();
$json = $document->toJson(JSON_PRETTY_PRINT);
$openApi = $document->toOpenApi();

如果希望直接生成数组或 JSON,可以使用生成器提供的快捷方法:

$array = OpenApiGenerator::toArray('default');
$json = OpenApiGenerator::toJson('default', JSON_PRETTY_PRINT);

底层 openapiphp\openapi\spec\OpenApiphp-openapi/openapi 提供,字段名称与 OpenAPI Specification 保持一致。未显式建模或 x-* 扩展字段也会由该包按规范处理。

return response()->json(OpenApiGenerator::toArray('default'));

文档缓存

为减少重复扫描路由和反射解析的开销,生成器默认会将每个文档分组的结果缓存 86400 秒。

'cache_enable' => true,
'cache' => [
    'ttl' => 86400,
    'store' => null,
],
  • cache_enable 默认开启,关闭后将完全跳过缓存逻辑。
  • APP_ENV=local 时也会直接跳过缓存,便于本地修改路由、控制器和 DocBlock 后即时生效。
  • cache.ttl 单位为秒,设置为 0 或更小值时表示关闭缓存。
  • cache.store 为空时使用 Laravel 默认缓存驱动,也可以指定单独的 store。

如果线上发布后需要主动清掉文档缓存,可以直接调用:

use SoftChen\LaravelOpenApi\OpenApiGenerator;

OpenApiGenerator::clearCache('default');

// 多域名场景下也可以显式传入 server URL
OpenApiGenerator::clearCache('default', 'https://api.example.com');

未传第二个参数时,会按当前请求根地址或 app.url 生成缓存 key。

路由过滤

route.includeroute.exclude 同时支持路由 URI 与路由名称,匹配规则使用 Laravel Str::is(),因此可以使用 * 通配符。

'route' => [
    'include' => [
        'api/*',
        'admin.*',
    ],
    'exclude' => [
        'api/internal/*',
    ],
],

include 为空时表示纳入全部路由,exclude 命中的路由会被剔除。

按 Middleware 标记登录

如果只有部分路由需要登录,可以配置 needLoginMiddleware。生成器会检查 route:list --json 输出里的 middleware 字段,只有命中这些 middleware 的路由才会带上 OpenAPI security

'needLoginMiddleware' => 'admin',
'openapi' => [
    'components' => [
        'securitySchemes' => [
            'Authorization' => [
                'type' => 'apiKey',
                'in' => 'header',
                'name' => 'Authorization',
            ],
        ],
    ],
    'security' => [
        ['Authorization' => []],
    ],
],

needLoginMiddleware 支持字符串、数组和 * 通配符;例如 ['admin', 'auth:*']。配置该项后,openapi.security 会作为“需要登录的接口”的默认鉴权要求,未命中的路由不会继承这段 security

DocBlock 说明

生成器会读取控制器类和方法的 DocBlock:

  • 控制器类摘要会作为 OpenAPI tags 名称。
  • 控制器方法摘要会作为接口 summary
  • 控制器方法描述会作为接口 description
/**
 * 用户管理
 */
class UserController
{
    /**
     * 用户列表
     *
     * 获取后台用户分页列表。
     */
    public function index()
    {
        //
    }
}

OpenAPI 根配置

openapi 配置项会合并到 OpenAPI 根节点,可用于补充 serversexternalDocscomponentssecurity 等信息。termsOfServicecontactlicense 属于 OpenAPI info 对象,建议写到 openapi.info 下。设置 needLoginMiddleware 后,openapi.security 会改为按命中的路由逐个写入,不再作为全局默认值输出。未配置 servers 时,生成器会默认使用当前请求根地址;如果当前没有 HTTP 请求,则回退到 app.url

'openapi' => [
    'openapi' => '3.0.3',
    'servers' => [
        ['url' => 'https://api.example.com'],
    ],
    'info' => [
        'termsOfService' => 'https://example.com/terms',
        'contact' => [
            'name' => 'API Support',
            'email' => 'support@example.com',
        ],
        'license' => [
            'name' => 'MIT',
            'url' => 'https://opensource.org/licenses/MIT',
        ],
    ],
    'components' => [
        'securitySchemes' => [
            'Authorization' => [
                'type' => 'apiKey',
                'in' => 'header',
                'name' => 'Authorization',
                'description' => '通用请求头中传入 Authorization,例如 Bearer {token}',
            ],
        ],
    ],
    'security' => [
        ['Authorization' => []],
    ],
],

如果你的项目是通过通用请求头传入 Authorization,可以直接使用上面的示例。这样生成的 OpenAPI 文档会声明全局鉴权方案,并应用到所有接口。

生成器会维护 info.titleinfo.descriptioninfo.version 以及 pathstags。如果只需要补充 info 里的其他字段,可以通过 openapi.info 配置;为兼容旧配置,写在 openapi 根层的 termsOfServicecontactlicense 也会自动归并到 info

如果你没有显式配置 openapi.servers,生成器会自动补一个默认值:

  • HTTP 请求上下文里使用当前请求根地址,例如 https://api.example.com
  • CLI 或其他拿不到请求的场景回退到 Laravel app.url

自定义处理器

如果需要补充请求体、响应结构、鉴权信息,或者按权限裁剪接口,可配置一个处理器:

'handler' => App\OpenApi\AdminOpenApiHandler::class,

推荐继承 SoftChen\LaravelOpenApi\Handlers\OpenApiHandler,这样可以直接使用封装好的公共方法,而不需要自己处理底层对象细节。旧版 transformer 配置键和 OpenApiTransformer 仍然兼容,但后续更建议统一迁移到 handler

namespace App\OpenApi;

use openapiphp\openapi\spec\Schema;
use SoftChen\LaravelOpenApi\Handlers\OpenApiHandler;

class AdminOpenApiHandler extends OpenApiHandler
{
    protected function process(): void
    {
        $this->describeOperation('/api/users/{id}', 'get', '用户详情', '根据用户 ID 获取后台用户详情。');
        $this->upsertPathParameter('/api/users/{id}', 'get', 'id', '用户 ID。', new Schema([
            'type' => 'integer',
            'format' => 'int64',
        ]));
    }
}

基础 OpenApiHandler 当前封装了这些常用公共方法。下面每个方法都默认在子类的 process() 中调用。

如果你的场景需要按数据库权限、租户配置或其他业务规则去掉部分接口,可以直接在 process() 里调用删除 helper:

protected function process(): void
{
    if (! $this->shouldExpose('users.export')) {
        $this->removeOperation('/api/users/export', 'post');
    }

    if (! $this->shouldExpose('internal.docs')) {
        $this->removePath('/api/internal/docs');
    }
}

removeOperation()

用途:删除某个路径下的单个 HTTP 接口;如果该路径下已经没有其他方法,会自动把整个 path 一并移除。

方法签名:

removeOperation(string $path, string $method): static

示例:

$this->removeOperation('/api/users/export', 'post');

removePath()

用途:删除整个 OpenAPI path 以及其下的所有接口定义。

方法签名:

removePath(string $path): static

示例:

$this->removePath('/api/internal/docs');

describeOperation()

用途:同时设置接口的 summarydescription,适合快速补齐接口中文说明。

方法签名:

describeOperation(string $path, string $method, ?string $summary = null, ?string $description = null): static

参数说明:

  • $path:OpenAPI 路径,例如 /api/users/{id}
  • $method:HTTP 方法,例如 getpost
  • $summary:接口标题,可传 null
  • $description:接口详细描述,可传 null

示例:

$this->describeOperation(
    '/api/users/{id}',
    'get',
    '用户详情',
    '根据用户 ID 获取后台用户详情。'
);

setOperationSummary()

用途:只设置接口标题,不改动接口描述。

方法签名:

setOperationSummary(string $path, string $method, string $summary): static

示例:

$this->setOperationSummary('/api/users', 'get', '用户列表');

setOperationDescription()

用途:只设置接口详细描述,不改动接口标题。

方法签名:

setOperationDescription(string $path, string $method, string $description): static

示例:

$this->setOperationDescription('/api/users', 'get', '分页获取后台用户列表,支持关键词搜索。');

upsertQueryParameter()

用途:新增或更新查询参数。如果参数已存在,会按 name + in 合并更新。

方法签名:

upsertQueryParameter(
    string $path,
    string $method,
    string $name,
    string $description,
    array|Schema $schema = ['type' => 'string'],
    bool $required = false,
): static

参数说明:

  • $name:查询参数名,例如 page
  • $description:参数中文说明
  • $schema:参数类型定义,推荐传 openapiphp\openapi\spec\Schema
  • $required:是否必填,默认 false

示例:

use openapiphp\openapi\spec\Schema;

$this->upsertQueryParameter('/api/users', 'get', 'page', '页码,从 1 开始。', new Schema([
    'type' => 'integer',
    'minimum' => 1,
]));

$this->upsertQueryParameter('/api/users', 'get', 'keyword', '搜索关键词。');

upsertPathParameter()

用途:新增或更新路径参数。该方法会自动把参数标记为 required = true

方法签名:

upsertPathParameter(
    string $path,
    string $method,
    string $name,
    string $description,
    array|Schema $schema = ['type' => 'string'],
): static

示例:

use openapiphp\openapi\spec\Schema;

$this->upsertPathParameter('/api/users/{id}', 'get', 'id', '用户 ID。', new Schema([
    'type' => 'integer',
    'format' => 'int64',
]));

setJsonRequestBody()

用途:设置 application/json 请求体,适合 POSTPUTPATCH 这类接口。

方法签名:

setJsonRequestBody(
    string $path,
    string $method,
    array|Schema $schema,
    bool $required = true,
    ?string $description = null,
): static

参数说明:

  • $schema:请求体 schema,可传 OpenAPI schema 数组
  • 推荐传 openapiphp\openapi\spec\Schema 对象
  • $required:请求体是否必填
  • $description:请求体说明

示例:

use openapiphp\openapi\spec\Schema;

$this->setJsonRequestBody('/api/users', 'post', new Schema([
    'type' => 'object',
    'required' => ['name', 'email'],
    'properties' => [
        'name' => [
            'type' => 'string',
            'description' => '用户名称。',
        ],
        'email' => [
            'type' => 'string',
            'format' => 'email',
            'description' => '登录邮箱。',
        ],
    ],
]), true, '创建用户请求体。');

setResponseDescription()

用途:设置指定响应状态码的描述;如果该响应不存在,会自动创建。

方法签名:

setResponseDescription(string $path, string $method, string|int $statusCode, string $description): static

示例:

$this->setResponseDescription('/api/users', 'post', 200, '创建成功。');
$this->setResponseDescription('/api/users/{id}', 'delete', 404, '用户不存在。');

document()

用途:获取当前 OpenApiDocument 对象。适合你需要直接访问底层完整文档时使用。

方法签名:

document(): OpenApiDocument

示例:

$document = $this->document();
$openApi = $document->toOpenApi();

context()

用途:获取当前转换上下文,可访问当前配置分组、配置内容和路由列表。

方法签名:

context(): OpenApiHandlerContext

示例:

$key = $this->context()->key;
$route = $this->context()->routeByName('users.show');

operation()

用途:读取某个接口对应的底层 Operation 对象;如果不存在,返回 null

方法签名:

operation(string $path, string $method): ?Operation

示例:

$operation = $this->operation('/api/users/{id}', 'get');

pathItem()

用途:读取某个路径对应的底层 PathItem 对象;如果不存在,返回 null

方法签名:

pathItem(string $path): ?PathItem

示例:

$pathItem = $this->pathItem('/api/users/{id}');

更完整的示例请看 examples/AdminOpenApiHandler.php,其中包含:

  • GET /api/users 添加接口描述。
  • keywordpageper_page 查询参数添加说明。
  • GET /api/users/{id}id 路径参数添加说明。
  • POST /api/users 添加 JSON 请求体字段说明。

路径需要使用生成后的 OpenAPI path,例如 Laravel 路由 api/users/{id} 对应 /api/users/{id}

转换时传入的是 SoftChen\LaravelOpenApi\Documents\OpenApiDocument 对象和 SoftChen\LaravelOpenApi\Handlers\OpenApiHandlerContext 对象。若继承基础 OpenApiHandler,可以通过 document()context() 访问它们。

$array = OpenApiGenerator::generate('default')->toArray();
$json = OpenApiGenerator::generate('default')->toJson(JSON_PRETTY_PRINT);

开发检查

composer analyse
composer format

更新日志

请查看 CHANGELOG

许可证

MIT License. 请查看 LICENSE.md