用于 API 响应的 Laravel 自定义包装器

Posted

技术标签:

【中文标题】用于 API 响应的 Laravel 自定义包装器【英文标题】:Laravel Custom Wrapper for API Responses 【发布时间】:2020-11-14 18:46:34 【问题描述】:

我正在尝试在刚刚创建的Laravel 中构建我的项目,以将其用作back-end API。我希望以官方网站上定义的JSON:API 格式返回来自Laravel 的所有回复:https://jsonapi.org/format/

例如: 我创建了以下 2 个资源文件:

1-php artisan make:resource User

2-php artisan make:resource UserCollection --collection

两个简单的资源文件,一个返回resource,一个返回collection

现在,我想在我的所有回复中返回以下格式:

如果是success

1-状态返回码可以是200201202

2- 返回的响应应该类似于以下内容:


    "data": [
        
            "id": 1,
            "email": "collins.elody@example.org"
        
    ],
    "message": null,
    "success": true

您可能想知道传递message 键有什么意义,在本例中是null,因为它将返回一个collection 记录,即读取 ,但如果您需要添加新记录、更新删除一条记录,则需要将消息传递给我的front-end ,在这种情况下,我会使用该密钥。

示例,添加记录,响应状态码201


    "data": [],
    "message": "Record created succesfully",
    "success": true

如果是failure

如这里所说:https://jsonapi.org/format/#document-top-level:成员数据和错误不能共存于同一个文档中。

所以,如果出现错误,我需要将data 密钥更改为errors 密钥,例如,假设我正在尝试验证自己,并且验证失败,在这种情况下,结果应该是这样的:


    "errors": 
        "email": "E-Mail is required",
        "password": "Password is required"
    ,
    "message": null,
    "success": false

或者我只想返回一个error message,预期的输出应该是:


    "errors": [],
    "message": "Something is Wrong!",
    "success": false

所以本质上,我需要的是一个全局包装器,用于我从 Laravel 中做出的所有响应。我想以一种优雅的方式调用 return 如下:

return $this->success($collection);

return $this->success('Done!', 201);

所以首先想到的是创建一个trait 并定义您需要的方法,然后从Laravel 中的任何位置调用它们

我的Trait

<?php

namespace App\Traits;

trait APIResponse

    public function success($data, $status = 200) 
        return [
            'data' => $data,
            'success' => in_array($status, [200, 201, 202]) ? true : false,
            'message' => null
        ];
    

    public function failure($data, $status = 500) 
        // TODO
    


我的Controller

class ExampleController extends Controller

    public function index() 

        $collection = new UserCollection(User::all());

        return $this->success($collection);
    


但我不确定这是正确的方法,请在该领域的技术人员可以帮助我。非常感谢您。

【问题讨论】:

【参考方案1】:

您走在正确的道路上,我认为有两种主要解决方案是处理您的确切问题的最佳方法。 Fractal 和 Eloquent Resources,由于一些设计决策和经验,我更喜欢 Fractal。

我将展示一个分形示例,使用wrapper by Spatie。首先创建一个序列化器,它将按预期包装数据。

class YourCustomSerializer extends SerializerAbstract

    public function collection($resourceKey, array $data)
    
        return [
            $resourceKey ?: 'data' => $data,
            'message': null,
            'success': true,
        ];
    

    public function item($resourceKey, array $data)
    
        return [
            $resourceKey ?: 'data' => $data,
            'message': null,
            'success': true,
        ];
    

这应该添加到您的 fractal.php 配置中,通过 spatie 包装器发布。

转换数据需要转换器。

class UserTransformer extends TransformerAbstract

    public function transform(User $user)
    
        return [
            'name' => $user->name,
            'email' => $user->email,
        ];
    

现在您可以将数据转换为预期的格式。

public function response($data, int $statusCode = Response::HTTP_OK)

    return fractal($data, $this->transformer)->respond($statusCode);

对于错误代码,您应该转到Handler.php 并添加与此类似的内容。这是一种非常幼稚的做法,但要知道应该让您继续进行错误处理,您需要对验证异常、状态代码等做一些事情。

if ($request->wantsJson()) 
    return response()->json([
        'success' => false,
        'message' => $exception->getMessage(),
    ], Response::HTTP_BAD_REQUEST);

【讨论】:

我不会做“添加记录”或类似的具体消息,这是浪费时间,只依赖成功真实或类似 关于 json api 规范,请记住这是一个非常自以为是的规范,它为了结构而添加了很多结构,参数始终是您可以使用客户端或类似的方式来使用您的 API练习到目前为止我从未见过。我认为你基于这个问题有多远,你需要找到自己的做和不做的路径。你以某种方式同意结构很好的规范,只是把它变成你自己的。 哇! @mrhn,感谢您的详细解释,我一直在阅读有关 Fractal 包的信息,但我从未阅读过它,因为我到目前为止已经阅读过,它在 Laravel 5.5 版之前使用,因为它使这种工作变得更加容易。我会尝试使用 Eloquent Resources,因为这是 Laravel 处理此类问题的官方方式……如果没有得到结果,我保证我会尝试 Fractal,然后我会告诉你我的经验。再次......一百万谢谢你给我的问题一个北方。- 幸运的是方法是相似的,你 EloquentResources 没有与序列化程序类似的概念

以上是关于用于 API 响应的 Laravel 自定义包装器的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5 - 在 Rest API 服务器上自定义 JSON 响应

如何自定义 laravel api 的 json 响应并在 vuex 中显示它们

使用自定义 json 响应进行 Laravel 验证

Laravel-自定义API返回的JSON格式

php 一个自定义的try..catch包装器代码片段,用于执行模型函数,使其成为一个单行函数调用

用于 maria-db 动态列的 Laravel 雄辩包装器