You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:07:48