使用 Laravel 的 API 资源功能来构建你的 API

file

在过去的2年时间里,我一直使用 Fractal 来进行 API 开发。

如果说一个我最希望 Laravel可以增加的功能的话,无疑是方便的数据转换,以便开发更好的 API 接口。

别误会, Fractal 很好用,然而我总是希望能只用框架进行开发。如果可以的话,我尽可能不使用类库!我不喜欢使用第三方类库使得开发复杂化。

在过去的一年里,我喜欢使用一些前端框架如 Vue 和 React 来进行开发。因此,我选择只使用 Laravel来建立 API 接口。 而当我需要建立 API 接口 的时候,Fractal是我首选的类库。 现在,情况发生了变化。

在 Laravel 5.5 中,我们有了 API 资源,对此,我真的是非常的兴奋。

在2小时前,Laravel 5.5 发布了,当时我正和朋友一起喝咖啡。当我在半小时前读到这条推的时候,脑子里的第一个想法就是用 API 资源来发布我的第一篇博客文章,我也确实这么做了。

Laravel 的 API 资源是基于 Fractal , 因此,我并没有花太多时间来了解如何使用它。 所以,让我们开始来了解它吧 ...

创建 Laravel 应用

用常用的命令行来创建 Laravel 应用

composer create-project laravel/laravel Laravel55Api

应用创建完成后,将 .env.example 重命名为 .env 并用以下命令生成 Laravel 密钥。

php artisan key:generate

启动服务

php artisan serve

很好,接下来是什么呢?

创建一个 Product 资源

API 资源是在 Laravel 中将你的模型以及模型集合转换为 JSON 的新特性。接下来让我们创建一个 Product 的资源。

php artisan make:resource Product

你可以在 app/Http/Resources 目录下看到你刚刚生成的 Product 资源

当然我们还需要 Product 的数据库迁移、模型和控制器。我们能用这个命令快速的创建这些。

php artisan make:model Product -mc

打开数据库迁移文件然后像这样修改 up 方法里面的内容:

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->integer('price');
        $table->timestamps();
    });
}

注意这里的价格字段是整型的。 我拜托你们,永远不要用浮点型存储你的价格数据!

一定要用整型来存储!

现在用你的 Laravel 应用连接数据库并运行这个迁移以生成数据表。

本文不是 Laravel 一对一教学贴,所以我不会在连接数据库的问题上浪费你过多的时间。

接下来?

到目前为止,我们已经有模型,控制器,数据库迁移以及用以转换模型和模型集合为 JSON 的资源类。那么接下来呢?

在这之前,什么是资源类?我们在 resources 文件夹中创建的 Product 类又是什么?一个资源类表示了单个模型转换为 JSON 的结构。

结合上面所阐述的,让我们来打开 Product.php 资源类文件。

这里有一个 toArray 方法,这个就是在我们发送响应时返回需要转换为 JSON 的属性数组的方法。

我们来修改它,让我们可以有更好的点子。

public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'price' => $this->price,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

现在表示我们能够获得有 id, name, price, created_atupdated_at 这些字段的响应。

如果我们在 toArray 方法中去掉 price 字段,返回的 JSON 中就不会有 price 。很酷不是吗?

使用 Product 资源

我们刚刚更改了 toArray 方法,让我们继续在我们的控制器中使用 product 资源。

product 控制器是看起来是这样的:

<?php

namespace App\Http\Controllers;

use App\Product;
use App\Http\Resources\Product as ProductResource;

class ProductController extends Controller
{
    public function show ($id)
    {
        return new ProductResource(Product::find($id));
    }
}

为了转换 product ,我们仅仅在 product 资源类中传递了一个 product

让我们创建一个 show 方法的路由,看一看结果。

打开 api.php 文件,在中间件外部创建这个路由。

Route::get('/products/{id}', 'ProductController@show');

现在,手动的在你的 products 表里添加一个新的 product,然后访问http://127.0.0.1:8000/api/products/1看看一个简单的 product

你应该得到这样的结果:

file

现在让我们来修改一点我们的资源,假如你不想公开你的 productprice,你要做的就是简单的从你的 toArray 方法删除它。一旦你从 toArray 方法删除了 price,你应该得到这样的结果,当然不包括 price

file

就这些吗?

当然不是!因为 toArray 方法仅仅是一个方法,它意味着你可以包含额外的信息。

假如我们想要包括一个「test」信息,简单的改变你的 toArray 方法。

public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'test' => 'This is just a test',
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

这是结果:

file

然而,非常要重的是,你希望返回的数据类型总是正确的。在第一个截图上看看 price,它返回的是一个 integer,但是通过 (int) $this->price,我们仍然要强制它是一个integer

现在,看看 create_atupdated_at 时间戳。如果你想要的是返回一个实际时间戳的字符串?那么你可以像这个例子中,强制类型转换为字符串:

public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'test' => 'This is just a test',
        'created_at' => (string)$this->created_at,
        'updated_at' => (string)$this->updated_at,
    ];
}

现在的结果是这个:

file

结束语

这仅仅是使用 Laravel API 资源的一个小例子。

如果我继续写下去,这篇文章永远也写不完。

所以,这篇文章就写到这吧,正如你所知道的,我们还有更多话题需要讨论,比如分页、资源集合、关联以及数据包裹等。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://medium.com/@devlob/creating-apis...

译文地址:https://learnku.com/laravel/t/7528/use-t...

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 27

表示价格一般用decimal

6年前 评论

@TimJuly 在设计price字段的时候,只要考虑以最小的单位为1基准就可以了,比如如果price是人民币的话,就以1分钱为1,那么1块钱存在数据库就是100。

6年前 评论

讲道理,这个比 Fractal 灵活简单太多了,Fractal 过度设计还不灵活,用了之后我都快神经分裂了

6年前 评论

fractal的 transformers的 include功能以及param的解析 功能我觉得很酷 ,
include=comments:limit(5|1):order(created_at|desc) 类似这样的处理. 如何在api resource中使用类似这样的功能,并且还不会带来n+1的问题呢

6年前 评论
world_hello 4年前

我拜托你们,永远不要用浮点型存储你的价格数据! 这句不太明白什么意思。为什么价格不能float呢?如果用decimal呢?

6年前 评论
keyboby 3年前

表示价格一般用decimal

6年前 评论
LOST

@遗忘的影子 感觉主要是误差不可控。

6年前 评论
TimJuly

不能以偏概全啊,整数存钱就是个大坑,如果非要这么干,一定要想清楚.

例如:现在有1块钱分给500个小朋友,请问每人得多少钱?

6年前 评论
幽弥狂

@KevinYang 我也是用的decimal。。。

6年前 评论
幽弥狂

@TimJuly decimal 啊 ,怎么存不是你说了算呢

6年前 评论

@TimJuly 2000

哦,其实就是 2 。 你给我我也找不开那种。

6年前 评论

@TimJuly 在设计price字段的时候,只要考虑以最小的单位为1基准就可以了,比如如果price是人民币的话,就以1分钱为1,那么1块钱存在数据库就是100。

6年前 评论
chenBJ

file

6年前 评论
GalaxyNo_1

价格一般都存分吧,没有存元的。:earth_africa:

6年前 评论

datetime 还可以这样转呢(string)$this->updated_at

6年前 评论

@Max 稍微复杂一点的就废了,像一个玩具

6年前 评论

@我是谁 但大多数应用追求的就是简单. 尤其是前后端分离 mvvm架构中, 后端只是提供一个数据接口而已.并不需要做太过复杂的处理

6年前 评论

@JaiminWu 其实最好的解决方案应该是decimal 不然等你处理到类似ETH这种数字货币的时候你就头大了 18位的小数点 你难道要* 10000000000000000 然后再处理么 不太可能的

5年前 评论

Resource 中 created_at 字段怎样返回 unix 格式呢?难道只能 strtotime( ) 转换吗?

5年前 评论
return [
        'id' => $this->id,
        'name' => $this->name,
        'test' => 'This is just a test',
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];

我想知道 $this->name 什么的 在编辑器里面标红 有什么办法解决的么?

已解决:
使用 下面的方式 就不会出现IDE飘红的问题了.

return [
        'id' => $this->resource->id,
        'name' => $this->resource->name,
        'test' => 'This is just a test',
        'created_at' => $this->resource->created_at,
        'updated_at' => $this->resource->updated_at,
    ];
4年前 评论

YII2是重写当前models的fileds方法,无需关注API,通过AR返回的数据会统一处理,代码如下:

public function fields()
{
    $fields = parent::fields();//返回所有表字段
    $fields['end_at'] = function ($model) {//格式化字段
        return !empty($model['end_at']) ? date('Y-m-d', $model['end_at']) : '';
    };
    unset($fields['password']);//删除不需要展示的字段
    return $fields;
}

我怎么觉得YII2更优雅呢:smile: ,restful api 也支持格式化响应,速率限制,版本化等等。

4年前 评论

我来啦,哈哈。帮大家补充个更详细的教程。 《用 Laravel 构建 RESTful API 教程》 kalasearch.cn/community/tutorials/...

觉得有用点个赞哈。

3年前 评论

分页集合index 和明细 show 返回需要的字段不一样,怎么处理?

3年前 评论

@Vicoo 建两个resource,一个用于列表,一个用于具体明细

3年前 评论

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