Laravel API资源按需返回关联数据:列表查询不加载详情
嘿,这个需求我之前做项目的时候正好碰到过,Laravel的API资源提供了几种很优雅的方式来实现这种按需返回关联数据的需求,既能解决列表查询加载慢的问题,又能保证详情页数据完整。我给你分享几个常用的方案:
方案一:使用Resource的when()方法(官方推荐)
Laravel的Resource类自带了when()方法,可以让我们根据条件动态添加字段。你可以直接在ExampleResource里通过判断请求场景(比如路由名称)来决定是否返回details:
use Illuminate\Http\Resources\Json\Resource; class ExampleResource extends Resource { public function toArray($request) { return [ "id" => $this->id, "user" => new UserResource($this->user), "total" => number_format($this->getTotal(), 2), // 只有当请求是详情接口时才返回details "details" => $this->when( // 假设你的详情路由名称是「examples.show」,列表是「examples.index」 $request->route()->getName() === 'examples.show', ExampleDetailsResource::collection($this->details) ), ]; } }
这样一来,当访问列表接口(比如/examples)时,details字段会自动被忽略;访问详情接口(比如/examples/1)时,就会正常返回关联的详情数据。
方案二:拆分列表和详情资源(职责更清晰)
如果你的资源后续可能要添加更多差异化字段,拆分资源会让代码更易维护。我们可以分别定义列表用的资源和详情用的资源:
列表资源(不含details)
use Illuminate\Http\Resources\Json\Resource; class ExampleListResource extends Resource { public function toArray($request) { return [ "id" => $this->id, "user" => new UserResource($this->user), "total" => number_format($this->getTotal(), 2), ]; } }
详情资源(包含details)
use Illuminate\Http\Resources\Json\Resource; class ExampleShowResource extends Resource { public function toArray($request) { return [ "id" => $this->id, "user" => new UserResource($this->user), "total" => number_format($this->getTotal(), 2), "details" => ExampleDetailsResource::collection($this->details), ]; } }
然后在控制器里对应使用:
// 列表接口 public function index() { // 只预加载user,不用加载details $examples = Example::with('user')->get(); return ExampleListResource::collection($examples); } // 详情接口 public function show($id) { // 预加载user和details,避免*N+1查询* $example = Example::with(['user', 'details'])->findOrFail($id); return new ExampleShowResource($example); }
重要注意事项:预加载优化性能
不管用哪种方案,预加载关联数据都是必须的!尤其是details数量多的时候,如果不预加载,会触发可怕的N+1查询,反而让接口变慢。所以一定要在控制器里用with()方法提前加载需要的关联模型。
内容的提问来源于stack exchange,提问作者Johhn
相关产品推荐
相关产品推荐

