Laravel 的 JsonResource 无法被文档生成器自动识别,因其动态逻辑(如 when、whenLoaded)与 OpenAPI 静态 schema 要求冲突;正确做法是在控制器方法上用 @response 或 @responseCollection 等注解显式声明响应结构,并严格同步字段名、类型及 nullable 状态。

不能让文档自动识别 API Resource 类。Laravel 的 JsonResource 是运行时数据转换工具,不是接口契约描述;所有主流文档生成器(如 Scribe、laravel-openapi)都明确不解析 toArray(),只认控制器方法上的显式注解。
为什么 Resource 类无法被自动识别
Resource 类设计目标是“把模型转成 JSON”,而非“声明接口结构”。它允许在 toArray() 中写任意 PHP 逻辑——比如 when() 动态字段、whenLoaded() 条件嵌套、构造器传参控制行为。这些动态性恰恰与 OpenAPI 要求的静态、可枚举 schema 冲突。
- 调用
UserResource::collection($users)不会触发任何 schema 分析,工具不会去读取UserResource的toArray() - 即使你写了
'posts' => $this->whenLoaded('posts', fn() => ...),文档也不会知道posts是数组、是否可为空、内部结构是什么 - 若资源构造器接收额外参数(如
new UserResource($user, $withMeta = true)),OpenAPI 更无法反推其对输出的影响
正确做法:在控制器方法上补全注解
文档生成依据是控制器动作方法的 PHPDoc,不是 Resource 类本身。你必须手动声明响应结构,哪怕 Resource 已经写得很完整。
- 单资源响应:在方法上加
@response App\Http\Resources\UserResource - 集合响应:用
@responseCollection App\Http\Resources\UserResource(不是@response) - 自定义包装结构(如返回
{"items": [...]}):必须用@response配合 JSON 示例,例如:/*** @response {"items": {"id": 1, "name": "John"}}*/ - 说明字段细节:用
@responseField显式标注,例如:@responseField name string 用户姓名@responseField posts[].id integer 帖子 ID@responseField is_admin boolean nullable 是否为管理员(仅管理员可见)
配合 Resource 类提升注解效率
虽然不能自动识别,但你可以让注解和 Resource 类保持同步,减少出错:
- 把
@responseField的字段名和类型,严格对应toArray()中的键和值类型(如'is_active' => (bool) $this->active→ 注解写@responseField is_active boolean) - 如果用了
$this->wrap = 'data',注解中 JSON 示例或@responseCollection就要体现"data"包裹层 - 对
whenLoaded('posts')这类嵌套,注解里写@responseField posts[].title string nullable,并加nullable标明条件性存在 - 日期字段统一格式后注解才准确,例如
'created_at' => $this->created_at?->format('Y-m-d H:i:s')→ 注解写@responseField created_at string date-time
常见踩坑点
很多团队以为写了 Resource 就等于有了文档基础,结果生成的文档空空如也或结构错乱:
- 只给控制器方法加了
@response却没指定类名,或写成@response UserResource(缺命名空间) - 返回分页集合却没链式调用
->response(),导致实际响应含links和meta,但注解仍按普通数组写,文档和真实结构对不上 - Resource 中用了访问器(如
getFullNameAttribute()),但注解字段名写成full_name而非full_name对应的原始键,造成前后端理解偏差 - 在
toArray()里做了敏感字段过滤(如跳过password),但注解里没删掉该字段,文档反而误导前端去取不存在的字段


















