如何优雅的去处理 API 数据格式

@这是小豪的第五篇文章
很多时候我们在构建 API 接口的时候会对数据进行二次处理,在没有接触 Laravel 的时候,我的处理方式总是从数据库中获取到数据,然后遍历去处理数据,很难看。。。今天我们来看看 Laravel 是如何处理的。

准备

我们用文章来举例:

class Post extends Model
{
    protected $fillable = [
        'user_id', 'title', 'content',
    ];

    /**
     * 获取文章作者
     * 
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
class PostController extends Controller
{
    public function index(Request $request)
    {
        return \response()->json(Post::all());
    }
}

访问器

“访问器”,顾名思义,就是对你需要访问的数据做处理的一个工具。
我们现在想给文章列表中的标题统一加一个 小豪 后缀,该怎么去定义访问器呢,现在我们来看一下 :

class Post extends Model
{
     protected $fillable = [
        'user_id', 'title', 'content',
     ];

    /**
     * 获取文章标题。
     *
     * @param  string  $value
     * @return string
     */
    public function getTitleAttribute($value)
    {
        return $value . "小豪";
    }
}

现在来看一下结果:
file

访问器定义的格式为: get + 驼峰字段名 + Attribute 。
是不是定义很简单呀,比遍历循环不知道好多少,哈哈。此时列表中 title 属性自动会加上 小豪 ,不需要再多处理了。
如果你想通过已有的属性,使用访问器返回新的计算值,可以这样定义 :

class Post extends Model
{
    protected $fillable = [
        'user_id', 'title', 'content',
    ];

    /**
     * 获取新的文章标题。
     *
     * @param  string  $value
     * @return string
     */
    public function getNewTitleAttribute($value)
    {
        return $this->user_id . "_" . $this->title;
    }
}

此时通过:$newTitle = $post->new_title 可以得到重新定义的新属性,如果说你想在列表中看到这个重新定义的属性,可以利用 appends 定义一个 new_title 属性,不太清楚模型属性的可以看一下《一些常用的模型属性》,是不是很棒哈哈。

API 资源

摘录一下文档中对 API 资源的介绍:
当构建 API 时,你往往需要一个转换层来联结你的 Eloquent 模型和实际返回给用户的 JSON 响应。Laravel 的资源类能够让你以更直观简便的方式将模型和模型集合转化成 JSON。

现在我们先来看一下,资源究竟该如何使用:
1. 首先我们创建一个资源类:

$ php artisan make:resource PostResource

来看一下 PostResource

class PostResource extends JsonResource
{
    /**
     * @param \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

2. 在控制器中使用:

class PostController extends Controller
{
    public function index(Request $request)
    {
        return new PostResource(Post::all());
    }
}

现在来看一下列表返回值:
file
已经自动给我们转换成 Json 格式的数据了。
大家可以看到 PostResource 中有一个 toArray 的方法,但是它是做什么用的呢?

class PostResource extends JsonResource
{
    /**
     * @param \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'user_id' => $this->user_id,
            'title' => $this->title,
        ];
    }
}

现在来看一下结果:
file
为什么报错了呢,因为 Post::all() 是一个集合,所以 PostResource$this 也是一个集合,所以 $this->id 什么的是不存在的,所以说 return new PostResource(Post::find(1)); 是可以兼容这种写法,因为 Post::find(1) 是个 post 实例不是集合哒,但是这里是列表也不可能用单个 post 实例, 该怎么去处理呢? Laravel 提供给了我们处理集合的方法:

class PostController extends Controller
{
    public function index(Request $request)
    {
        return PostResource::collection(Post::all());
    }
}

现在再来看一下结果:
file

我们想通过 PostResource 加载用户的信息:

class PostResource extends JsonResource
{
    /**
     * @param \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'user' => $this->user
        ];
    }
}

来看一下结果:
file
user 详情这里没有用资源去处理,不要在意,哈哈,这里的 $this->user 不清楚的,建议看一哈 《如何更快的找到自己所需的模型关联类型?》

现在我们来看一下分页:

class PostController extends Controller
{
    public function index(Request $request)
    {
        return \response()->json(Post::paginate());
    }
}

没有使用 API 资源 的时候我们来看一下结果:
file
是不是看着很糟心,我们来看看用 API 资源 之后的效果:

class PostController extends Controller
{
    public function index(Request $request)
    {
        return PostResource::collection(Post::paginate());
    }
}

file
哈哈,是不是赏心悦目的感觉。

结束语

API 资源 还有很多的好功能,我就不在这里一一讲解哒,哈哈,大家可以从文档中获得更多:《Eloquent: API 资源》,多练练手,很快就能熟悉了的,大家可能会问,还有一个 资源集合 没有讲到,其实吧,大体都类似,也不常用我就没在这里说哒,后面要是有需要我就加上来。
是不是很优雅,哈哈。

本作品采用《CC 协议》,转载必须注明作者和本文链接
finecho # Lhao
本帖由系统于 5年前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 10

高产似母猪

5年前 评论

这个links meta 的key哪里来的

file

5年前 评论
finecho

@lovecn 框架已经封装好了的噢,数据库: 分页

5年前 评论
Shuyi

我一般用的是Fractal,那个和软件设计模式更贴合 (Transformer), 他根据Model转换,不过讨厌的就是不知道怎么加参数进去。。。不过都有各自的好处,哈哈哈

5年前 评论
finecho

@Shuyi 哈哈,我没用过 Fractal ,后面学习一哈 :blush:

5年前 评论
kevin_yang

好期待下次更新

5年前 评论
庞浩然Paul

@Shuyi 我也想知道怎么加参数更规范。

5年前 评论
Shuyi

@庞浩然Paul 这个设计的意思就是要你不要加参数, 所以我就认了。

5年前 评论
finecho

@overtrue 哈哈,但是感觉质量没有之前的好了 :bowtie:,还是不能忘了写文章的初心

5年前 评论
guanhui07

高产 ,赞

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!