前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Api 开发之include机制

Api 开发之include机制

作者头像
切图仔
发布2022-09-14 14:59:55
1.3K0
发布2022-09-14 14:59:55
举报
文章被收录于专栏:生如夏花绚烂
概述

include英译:包含,包括,使成为...的一部分

我们在进行API开发时可能会将数据以及与该数据相关的数据全部发送给客户端,如 文章数据,相关的数据有“用户”,“分类”...

如下例

代码语言:javascript
复制
public function index(Request $request, Topic $topic)
    {
        $query = $topic->query();
        if ($categoryId = $request->category_id) {
            $query->where('category_id', $categoryId);
        }
        $topics = $query
        ->with('user', 'category')
        ->withOrder($request->order)
        ->paginate();

        return TopicResource::collection($topics);
    }

返回的结果 可以看到,除了返回文章相关数据外,还返回了用户相关数据

这样做不太友好,因为我们不知道客户端是否需要某些数据,如这里的“用户”。 没必要的数据增加了数据库操作,增加了数据响应。

正确的做法应该是,服务端返回基础数据,在根据客户端传参返回其相关联的数据

如何实现?

通过laravel第三方扩展包 spatie/laravel-query-builder 官方文档:https://docs.spatie.be/laravel-query-builder/v2/introduction/

1.composer 引入

代码语言:javascript
复制
composer require spatie/laravel-query-builder

2.控制器使用

代码语言:javascript
复制
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;

public function index(Request $request, Topic $topic)
    {

        $topics = QueryBuilder::for(Topic::class)
            ->allowedIncludes('user','category')//可以被include的参数
            ->allowedFilters([//允许过滤搜索的字段
                'title',//模糊搜索title
                AllowedFilter::exact('category_id'),//精确搜索category_id字段
                AllowedFilter::scope('withOrder')->default('recentReplied'),//本地作用域,传递默认参数
            ])
            ->paginate();

        return TopicResource::collection($topics);
    }

这里主要设计到两个方法 allowedIncludes:指定可被include的参数 客户端输入 include=user 可动态返回文章,用户的信息 include=user,category 返回文章,用户,分类的信息

allowedFilters:指定允许被过滤的字段,可以用作搜索 直接键入title表示模糊搜索

客户端 fillter[title]=none模糊查找title包含none的文章

AllowedFilter::exact('category_id'):表示精确过滤的字段 我们还可以键入某个scope(查询作用域)对数据进一步过滤,本文使用了定义好的withOrder作用域

代码语言:javascript
复制
//调用排序函数
    public function scopewithOrder($query,$order)
    {
        switch($order){
            case "recent":
                $query->recent();
            break;
            default :
                $query->RecentReplied();
        }
    }

利用postMan调试接口 1.基础数据

2.关联数据

上面的方式已经很好的解决了我们的问题,但是代码不够精炼,试想如果我们每个资源都要使用include机制那每个方法都会键入类似如下代码

代码语言:javascript
复制
$topics = QueryBuilder::for(Topic::class)
        ->allowedIncludes('user','category')//可以被include的参数
        ->allowedFilters([//允许过滤搜索的字段
                'title',//模糊搜索title
                AllowedFilter::exact('category_id'),//精确搜索category_id字段
                AllowedFilter::scope('withOrder')->default('recentReplied'),//本地作用域,传递默认参数
        ])
        ->paginate();

解决办法:为每个模型类添加一个Queries类 在这个Queries类里面键入上面逻辑,控制器使用时只需将该类依赖注入即可 1.新键Queries

代码语言:javascript
复制
mkdir  app/Http/Queries
touch app/Http/Queries/TopicQuery.php

2.在TopicQuery.php键入如下代码

代码语言:javascript
复制
<?php

namespace App\Http\Queries;

use App\Models\Topic;
use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;

class TopicQuery extends QueryBuilder
{
    public function __construct()
    {
        parent::__construct(Topic::query());
        $this->allowedIncludes('user', 'category')
            ->allowedFilters([
                'title',
                AllowedFilter::exact('category_id'),
                AllowedFilter::scope('withOrder')->default('recentReplied'),
            ]);
    }
}

控制器使用依赖注入

代码语言:javascript
复制
public function index(Request $request, TopicQuery $query)
    {
        $topics = $query->paginate();

        return TopicResource::collection($topics);
    }

可以看到代码精炼了许多

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 如何实现?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档