api resource 是 laravel 推荐的模型转 json 标准方式;它通过 toarray() 控制字段、关系、格式化,避免敏感数据泄露,需注意加载时机、分页处理及响应生命周期。

API Resource 是 Laravel 中将模型转为 JSON 的标准方式,不是可选项,而是推荐路径;直接用 $model->toJson() 或 response()->json($model) 会绕过字段控制、关系处理和条件逻辑,容易暴露敏感数据或漏掉格式化。
Resource 类的 toArray 方法决定最终 JSON 结构
资源类不修改模型本身,只定义“该输出什么”。toArray() 返回的数组就是响应体的根内容,所有字段命名、嵌套、格式转换都在这里完成。
- 日期必须显式调用
->toISOString()或->format(),否则默认是对象(触发 PHP 的__toString,结果不可控) - 关联数据不能直接写
'posts' => $this->posts,要改用'posts' => PostResource::collection($this->whenLoaded('posts')),否则未加载时会触发 N+1 或空集合报错 - 计算属性(如头像 URL)建议封装成访问器,再在
toArray()中引用,避免重复逻辑 - 字段重命名直接赋值即可,比如
'user_id' => $this->id,不用额外映射层
单个模型 vs 集合:别混用 new UserResource($user) 和 UserResource::collection($users)
两者返回类型不同:UserResource 实例返回一个对象结构,UserResource::collection() 返回带 data 包裹的数组结构(含分页元信息),控制器里不能互换使用。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 查单条(show):直接
return new UserResource($user),Laravel 自动包装为 JSON 响应 - 查列表(index):必须用
UserResource::collection($users),否则分页对象(LengthAwarePaginator)不会被正确解析 - 手动调用
toArray()后再response()->json()会丢失分页元数据(links,meta),除非你额外调用with() - 如果集合是普通数组(非 Eloquent Collection),需先转为
collect($array)再传给::collection(),否则会报错
控制器里返回 Resource 的三种写法,效果其实不同
看似都能出 JSON,但序列化时机、错误捕获点、中间件介入位置都不同。
-
return new UserResource($user):最推荐。Laravel 在响应发送前自动调用toResponse(),支持中间件(如 CORS)、异常处理器统一接管 -
return response()->json((new UserResource($user))->resolve()):提前触发序列化,绕过 Resource 的响应生命周期,with()、additional()失效 -
return response()->json($user->toArray()):完全跳过 Resource,等同于裸模型输出,$hidden和$casts虽仍生效,但无条件字段(when())、无关系嵌套、无统一结构保障 - 匿名资源(
Resource::make($user)->map(...))适合一次性简单映射,但无法复用、不能缓存、IDE 不友好,别在核心接口里用
容易被忽略的细节:whenLoaded、when、preserveKeys 会影响实际输出
这些方法不是装饰语法糖,它们直接改变序列化行为,且顺序和上下文很关键。
-
whenLoaded('posts')只有在控制器中明确调用了$user->load('posts')或模型已预加载,才会渲染字段;否则字段彻底消失,不是 null -
when($user->hasVerifiedEmail(), [...])的闭包里不能依赖未加载的关系,否则可能在判断时触发额外查询 -
preserveKeys(true)会让集合响应不加data包裹,但分页元信息(meta,links)也会丢,除非手动补全 - 资源类里重写
with()方法添加公共字段(如'success' => true)只对当前资源生效;全局统一结构建议用响应宏或中间件,而非每个 Resource 都写一遍
Resource 的真正复杂点不在写法,而在加载时机与序列化时机的错位——模型没 load() 关系,whenLoaded 就是静默失效;控制器返回了 Resource,但中间件想改状态码,得在 toResponse() 里动手,而不是在控制器里塞 response()->json(...)->setStatusCode(...)。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










