如何优雅的去处理 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 . "小豪";
}
}
现在来看一下结果:
访问器
定义的格式为: 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());
}
}
现在来看一下列表返回值:
已经自动给我们转换成 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,
];
}
}
现在来看一下结果:
为什么报错了呢,因为 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());
}
}
现在再来看一下结果:
我们想通过 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
];
}
}
来看一下结果:
( user
详情这里没有用资源
去处理,不要在意,哈哈,这里的 $this->user
不清楚的,建议看一哈 《如何更快的找到自己所需的模型关联类型?》)
现在我们来看一下分页:
class PostController extends Controller
{
public function index(Request $request)
{
return \response()->json(Post::paginate());
}
}
没有使用 API 资源
的时候我们来看一下结果:
是不是看着很糟心,我们来看看用 API 资源
之后的效果:
class PostController extends Controller
{
public function index(Request $request)
{
return PostResource::collection(Post::paginate());
}
}
哈哈,是不是赏心悦目的感觉。
结束语
API 资源
还有很多的好功能,我就不在这里一一讲解哒,哈哈,大家可以从文档中获得更多:《Eloquent: API 资源》,多练练手,很快就能熟悉了的,大家可能会问,还有一个 资源集合
没有讲到,其实吧,大体都类似,也不常用我就没在这里说哒,后面要是有需要我就加上来。
是不是很优雅,哈哈。
本作品采用《CC 协议》,转载必须注明作者和本文链接
这个links meta 的key哪里来的
@lovecn 框架已经封装好了的噢,数据库: 分页
我一般用的是Fractal,那个和软件设计模式更贴合 (Transformer), 他根据Model转换,不过讨厌的就是不知道怎么加参数进去。。。不过都有各自的好处,哈哈哈
@Shuyi 哈哈,我没用过 Fractal ,后面学习一哈 :blush:
好期待下次更新
@Shuyi 我也想知道怎么加参数更规范。
@庞浩然Paul 这个设计的意思就是要你不要加参数, 所以我就认了。
高产似母猪
@overtrue 哈哈,但是感觉质量没有之前的好了 :bowtie:,还是不能忘了写文章的初心
高产 ,赞