tttptd / laravel-responder
这是一个用于API的Laravel包,它将Fractal库包装在一个优雅的Laravel API后面。
这个包的规范存储库似乎已经消失,因此该包已被冻结。
Requires
- php: ^7.0
- illuminate/support: 5.1.* || 5.2.* || 5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*
- league/fractal: >=0.14.0
Requires (Dev)
- doctrine/dbal: ^2.5
- fzaninotto/faker: ^1.6
- illuminate/database: 5.1.* || 5.2.* || 5.3.*
- mockery/mockery: ^0.9.5
- orchestra/testbench: ~3.0
- phpunit/phpunit: ^5.4
- dev-master
- 1.2.28
- 1.2.27
- 1.2.26
- v1.2.25
- v1.2.24
- v1.2.23
- v1.2.22
- v1.2.21
- v1.2.20
- v1.2.19
- v1.2.18
- v1.2.17
- v1.2.16
- v1.2.15
- v1.2.14
- v1.2.13
- v1.2.12
- v1.2.11
- v1.2.10
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.18
- v1.0.17
- v1.0.16
- v1.0.15
- v1.0.14
- v1.0.13
- v1.0.12
- v1.0.11
- v1.0.10
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.3.0
- v0.2.26
- v0.2.25
- v0.2.24
- v0.2.23
- v0.2.22
- v0.2.21
- v0.2.20
- v0.2.19
- v0.2.18
- v0.2.17
- v0.2.16
- v0.2.15
- v0.2.14
- v0.2.13
- v0.2.12
- v0.2.11
- v0.2.10
- v0.2.9
- v0.2.8
- v0.2.7
- v0.2.6
- v0.2.5
- v0.2.4
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
This package is not auto-updated.
Last update: 2019-11-29 04:28:53 UTC
README
Laravel Responder是一个用于你的JSON API的包,将Fractal集成到Laravel和Lumen中。它可以转换你的Eloquent模型和序列化你的成功响应,但它也可以帮助你构建错误响应,处理异常,并集成测试你的API。
目录
哲学
在构建强大的API时,您想要确保您的端点对您的应用程序来说是一致的和易于使用的。Laravel非常适合您的API,但它缺乏对转换器和序列化器等常用工具的支持。另一方面,Fractal有一些非常好的工具用于构建API,并填补了Laravel的空白。
虽然Fractal解决了Laravel的许多不足,但将其集成到框架中通常有些繁琐。以控制器中的这个例子为例
public function index() { $manager = new Manager(); $resource = new Collection(User::get(), new UserTransformer(), 'users'); return response()->json($manager->createData($resource)->toArray()); }
我承认,Fractal管理器可以被移出控制器,并且您可以直接返回数组。然而,一旦您想要不同的状态码而不是默认的200,您可能仍然需要将其包装在response()->json()中。
重点是,我们都因为Laravel的魔法而有点被宠坏了。如果上面的内容可以写成以下这样,那岂不是很好
public function index() { return responder()->success(User::all()); }
该包将在幕后调用Fractal,以自动转换和序列化数据。不再需要根据它是模型还是集合而实例化不同的Fractal资源,该包自动处理所有这些。
要求
此包需要
- PHP 7.0+
- Laravel 5.1+ 或 Lumen 5.1+
安装
通过Composer安装此包
composer require flugger/laravel-responder
Laravel
注册服务提供者
更新Composer后,将以下服务提供者添加到config/app.php中的providers键
Flugg\Responder\ResponderServiceProvider::class
注册外观
如果您喜欢外观,也可以将Responder外观添加到aliases键
'Responder' => Flugg\Responder\Facades\Responder::class
发布包资产
您还可以使用Artisan命令发布包配置和语言文件
php artisan vendor:publish --provider="Flugg\Responder\ResponderServiceProvider"
这将发布一个位于您的config文件夹中的responder.php配置文件。
它还会在您的lang/en文件夹中发布一个errors.php文件,用于存储您的错误消息。
卢门
注册服务提供商
通过在 app/bootstrap.php 中添加以下行来注册包服务提供商
$app->register(Flugg\Responder\ResponderServiceProvider::class);
注册门面
您还可以将以下行添加到 app/bootstrap.php 以注册可选门面
class_alias(Flugg\Responder\Facades\Responder::class, 'Responder');
请记住取消注释 $app->withFacades(); 以在卢门中启用门面。
发布包资产
卢门中没有 php artisan vendor:publish,因此如果您想配置该包,您必须自己创建 config/responder.php 文件。请注意,与 Laravel 不同,没有 resources/lang 文件夹。但是,您可以手动创建 resources/lang/en/errors.php,并且它将被包识别。
使用方法
该包有一个 Flugg\Responder\Responder 服务,该服务负责为您构建 API 的成功和错误响应。
访问响应器
在您开始制作 JSON 响应之前,您需要访问响应器服务。遵循良好的 Laravel 精神,您有多种方式来完成同一件事
选项 1:依赖注入
您可以将响应器服务直接注入到控制器中以创建成功响应
public function index(Responder $responder) { return $responder->success(User::all()); }
您还可以创建错误响应
return $responder->error('invalid_user');
选项 2:门面
可选地,您可以使用 Responder 门面来创建响应
return Responder::success(User::all());
return Responder::error('invalid_user');
选项 3:辅助方法
此外,如果您喜欢 Laravel 的 response() 辅助方法,您可以使用 responder() 辅助方法
return responder()->success(User::all());
return responder()->error('invalid_user');
辅助方法和门面只是访问响应器服务的方式的不同,因此您可以使用相同的方法。
选项 4:特性
最后,该包还有一个您可以在基控制器中使用的 Flugg\Responder\Traits\RespondsWithJson 特性。
该特性为您提供了控制器中的 successResponse() 和 errorResponse() 方法
return $this->successResponse(User::all());
return $this->errorResponse('invalid_user');
这些方法在幕后调用响应器服务。
如上所述,您可以用多种方式构建响应。您选择哪种方式取决于您,重要的是要保持一致性。为了简化,我们将使用门面继续文档的其余部分。
成功响应
响应器服务有一个 success() 方法,您可以使用它来快速生成成功的 JSON 响应
public function index() { return Responder::success(User::all()); }
此方法返回一个 \Illuminate\Http\JsonResponse 实例,并在将其包装在 JSON 响应之前对其进行转换和序列化。
设置转换数据
success 方法的第一个参数是转换数据。如果设置了转换器,转换数据将被转换,并且必须是以下类型之一
Eloquent 模型
您可以传递模型作为转换数据
return Responder::success(User::first());
集合
您也可以传递模型集合
return Responder::success(User::all());
数组
您也可以传递模型数组
return Responder::success([User::find(1), User::find(2)]);
数组必须包含实际的模型实例,这意味着您不能使用 User::all()->toArray() 作为转换数据。
查询构建器
您可以直接传递查询构建器而不是将其转换为集合
return Responder::success(User::where('id', 1));
然后,该包将自动将分页信息添加到序列化器定义的响应中。
分页器
此外,您还可以通过传递分页器来限制项目数量
return Responder::success(User::paginate(5));
然后,该包将自动根据您使用的哪个 序列化器 将分页信息添加到响应中。
关系
您还可以传递 Eloquent 关系实例
return Responder::success(User::first()->roles());
包括关系
当使用 Fractal 时,您可以通过在管理器上调用 parseIncludes() 方法来包含关系,并在您的转换器中将可用的关系添加到 $availableIncludes 数组中。
使用 Laravel Responder,您不必做任何这些事情。它与 Eloquent 紧密集成,并自动解析模型加载的关系
return Responder::success(User::with('roles.permissions')->get());
您还可以让包自动解析并包括来自给定 GET 参数的关系,只需确保在配置中设置了 load_relations_from_parameter 键。
设置状态码
默认情况下,状态码设置为 200,但可以通过向 success() 方法添加第二个参数轻松更改。
return Responder::success(User::all(), 201);
有时您可能不希望返回任何内容。在这种情况下,您可以传递第一个参数为 null 或完全省略它。
return Responder::success(201);
添加元数据
您可能希望将额外的元数据传递到响应中,您可以通过添加第三个额外参数来实现。
return Responder::success(User::all(), 200, ['foo' => 'bar']);
如果您想发送默认的 200 响应,可以省略状态码。
return Responder::success(User::all(), ['foo' => 'bar']);
转换器
转换器负责将您的 Eloquent 模型转换为 API 的数组。转换器可以与模型关联,这意味着您的数据将自动转换,而无需指定转换器。
您可以在下面的几章中了解更多关于模型与转换器之间映射的信息。
转换数据
使用success()方法时,该包将尝试从转换数据中的模型解析转换器。如果没有找到转换器,将返回模型的toArray()字段。
如果您想明确指定要使用哪个转换器,可以在响应者服务上调用transform()方法。
return Responder::transform(User::all(), new UserTransformer)->respond();
除了使用完整的转换器类之外,您还可以传递一个闭包。
return Responder::transform(User::all(), function ($user) { return [ 'id' => (int) $user->id, 'email' => (string) $user->email ]; })->respond();
如果没有传递转换器,它将像success()方法一样表现。
return Responder::transform(User::all())->respond();
与success()方法不同,transform()方法返回一个Flugg\Responder\Http\SuccessResponseBuilder实例,这就是为什么我们要用respond()来链式调用,将其转换为Illuminate\Http\JsonResponse。
您还可以使用respond()方法设置状态码或头信息。
return Responder::transform(User::all())->respond(201, ['x-foo' => 'bar']);
您还可以使用addMeta()方法添加任何元数据。
return Responder::transform(User::all())->addMeta(['foo' => 'bar'])->respond();
正如您所猜测的,Responder::success($data, $status, $meta)方法只是调用Responder::transform($data)->addMeta($meta)->respond($status)的快捷方式。
通过使用serializer()方法,您还可以显式设置序列化器。
return Responder::transform(User::all())->serializer(new JsonApiSerializer)->respond();
您还可以使用include()方法手动包含关系,这是Fractal自己的parseIncludes()方法的包装。
return Responder::transform(User::all())->include('roles.permissions')->toArray();
除了使用respond()之外,您还可以将其转换为其他几种类型。
return Responder::transform(User::all())->toArray();
return Responder::transform(User::all())->toCollection();
return Responder::transform(User::all())->toJson();
您还可以检索Fractal资源或管理器实例。
return Responder::transform(User::all())->getResource();
return Responder::transform(User::all())->getManager();
创建转换器
该包提供了一个Artisan命令,您可以使用它快速创建新的转换器。
php artisan make:transformer UserTransformer
这将创建一个位于app/Transformers文件夹中的新的UserTransformer.php。
它将自动解析要注入的模型。例如,在上面的示例中,包将提取User从UserTransformer,并假设模型直接位于应用文件夹中(如Laravel的默认设置)。
如果您将模型存储在其他位置,您还可以使用--model选项指定模型路径。
php artisan make:transformer UserTransformer --model="App\Models\User"
您还可以使用--pivot选项包含一个额外的transformPivot()方法,用于转换模型的交叉表。
php artisan make:transformer UserTransformer --pivot
设置可用关系
就像您可以使用Fractal设置$availableIncludes一样,您在转换器上也有一个$relations属性。默认情况下,它将允许所有关系。
protected $relations = ['*'];
您还可以选择为转换器中的每个关系创建一个方法,如果您想根据解析的参数进行过滤。例如,如果您有一个roles包含,您可以创建一个roles()方法。
public function roles(User $user, ParamBag $paramBag) { // }
请注意,roles()方法接受一个User模型作为第一个参数,您可以在Fractal的文档中了解更多信息。
将转换器映射到模型
在许多情况下,您希望在每次引用模型时都使用相同的转换器。您不必为每个响应传递转换器,可以将转换器映射到模型,这样模型就会被自动转换。
要将转换器映射到模型,您的模型需要实现Flugg\Responder\Contracts\Transformable接口。该接口要求一个静态的transformer()方法,该方法应返回一个转换器。
class Role extends Model implements Transformable { /** * The transformer used to transform the model data. * * @return Transformer|callable|string|null */ public static function transformer() { return RoleTransformer::class; } }
transformer()方法也可以返回一个闭包转换器。
public static function transformer() { return function ($user) { return [ 'id' => (int) $user->id, 'email' => (string) $user->email ]; }; }
序列化器
在您的模型被转换之后,数据将使用设置的序列化器进行序列化。序列化器以某种方式结构化您的数据输出,但也可以添加额外的数据,如分页和元数据。
默认序列化器
该软件包自带默认序列化器,Flugg\Responder\Serializers\ApiSerailizer。以下是一个示例响应,假设有一个关联角色的用户
{
"status": 200,
"success": true,
"data": {
"id": 1,
"email": "example@email.com",
"role": {
"name": "admin"
}
}
}
响应输出与Laravel的默认输出非常相似,除了它将数据包装在data字段中。它还包含一个success字段,以便快速告知用户请求是否成功。
status字段实际上不是默认序列化器的一部分,而是在数据序列化后由包添加的。您可以在配置文件中禁用此功能。
Fractal序列化器
如果默认序列化器不符合您的口味,您可以轻松将其替换为Fractal附带的三种序列化器之一。
ArraySerializer
使用League\Fractal\Serializers\ArraySerializer的上述示例将看起来如下所示
{
"id": 1,
"email": "example@email.com",
"role": {
"name": "admin"
}
}
DataArraySerializer
您还可以使用League\Fractal\Serializers\DataArraySerializer添加data字段
{
"data": {
"id": 1,
"email": "example@email.com",
"role": {
"data": {
"name": "admin"
}
}
}
}
请注意,在这种情况下,data字段也适用于每个关系,这与默认包序列化器不同。
JsonApiSerializer
Fractal还使用League\Fractal\Serializers\JsonApiSerializer来表示JSON-API标准
{
"data": {
"type": "users",
"id": 1,
"attributes": {
"email": "example@email.com"
},
"relationships": {
"role": {
"data": {
"type": "roles",
"id": 1
}
}
}
},
"included": {
"role": {
"type": "roles",
"id": 1,
"attributes": {
"name": "admin"
}
}
}
}
如您所见,它相当冗长,但确实有其用途。
自定义序列化器
如果上述任何序列化器都不符合您的口味,您可以自由创建自己的,并在配置文件中将serializer键设置为指向您的序列化器类。您可以在Fractal的文档中了解更多关于如何创建自己的序列化器的信息。
错误响应
就像成功响应一样,当事情没有按计划进行时,您同样可以轻松地生成错误响应,使用error()方法
public function index() { return Responder::error(); }
就像成功响应一样,此方法返回一个\Illuminate\Http\JsonResponse实例,上面的示例将返回以下JSON
{
"status": 500,
"success": false,
"error": null
}
设置错误代码
error()方法的第一个参数是错误代码,可以是任何字符串值
if (request()->has('bomb')) { return Responder::error('bomb_found'); }
上面的示例将包含一个带有设置错误代码的错误对象
{
"status": 500,
"success": false,
"error": {
"code": "bomb_found",
"message": null
}
}
设置状态代码
错误响应的默认状态代码为500。但是,您可以通过传入第二个参数来更改状态代码
return Responder::error('bomb_found', 400);
您也可以省略错误代码
return Responder::error(400);
设置错误消息
您可能还希望为响应提供更详细的错误消息。您可以通过向error()方法添加第三个参数来实现
return Responder::error('bomb_found', 500, 'No explosives allowed.');
这将输出以下JSON
{
"status": 500,
"success": false,
"error": {
"code": "bomb_found",
"message": "No explosives allowed."
}
}
您还可以选择在响应默认状态代码为500时省略第二个参数
return Responder::error('bomb_found', 'No explosives allowed.');
使用语言文件
您可能在多个地方返回相同的错误响应。与其为每个响应设置消息,您可以使用errors.php语言文件。在您发布供应商资源后,此文件应位于您的resources/lang/en文件夹中。
如果您使用Lumen,则需要手动创建resources/lang/en/errors.php文件。您可以简单地复制默认语言文件。
语言文件包含以下默认错误消息
'resource_not_found' => 'The requested resource does not exist.', 'unauthenticated' => 'You are not authenticated for this request.', 'unauthorized' => 'You are not authorized for this request.', 'relation_not_found' => 'The requested relation does not exist.', 'validation_failed' => 'The given data failed to pass validation..',
这些消息用于Laravel的默认异常,该包可以捕获并将其转换为错误JSON响应。我们将在下一节异常中更详细地了解如何捕获这些异常。
让我们添加bomb_found错误代码并将其映射到相应的消息
'bomb_found' => 'No explosives allowed.',
然后您可以从错误响应中引用它
return Responder::error('bomb_found');
这将输出与上面相同的JSON,其中设置了错误消息
{
"status": 500,
"success": false,
"error": {
"code": "bomb_found",
"message": "No explosives allowed."
}
}
异常
当发生意外情况时,您可能更愿意抛出实际的异常,而不是使用error()方法。即使您不这样做,您可能也希望包捕获Laravel的默认异常,并自动将它们转换为JSON错误响应。
处理异常
如果您让包处理异常,该包将捕获所有扩展Flugg\Responder\Exceptions\Http\ApiException的异常并将它们转换为JSON响应。
要使用包异常处理器,您需要替换app/Exceptions/Handler.php中的以下行
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
使用包异常处理器
use Flugg\Responder\Exceptions\Handler as ExceptionHandler;
Lumen使用不同的基本异常处理器,与包异常处理器不兼容。您可以选择,简单地复制包异常处理器的内容,并将其粘贴到您的render()方法中,并使用Flugg\Responder\Traits\HandlesApiErrors特质。
捕获Laravel异常
当事情出错时,Laravel会抛出一些异常。例如,当使用findOrFail()方法找不到模型时,会抛出Illuminate\Database\Eloquent\ModelNotFoundException异常。如果您添加了包异常处理,这个异常和其他异常将被处理,如上段所述。
由于异常过于通用,从表单请求抛出的授权和验证异常无法自动捕获。但是,您可以在您的基请求类中使用Flugg\Responder\Traits\ThrowsApiErrors
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Flugg\Responder\Traits\ThrowsApiErrors; abstract class Request extends FormRequest { use ThrowsApiErrors; }
此特质会抛出扩展Flugg\Responder\Exceptions\Http\ApiException的异常,因此它们会被包异常处理器捕获。
从Laravel 5.3开始,不再提供基请求类。您可以选择手动创建一个,或者在每个表单请求中使用特质。
创建自定义异常
包包含一些异常以处理Laravel的默认异常。但是,您可能希望为您的API创建自己的异常。如果您希望包自动将您的异常转换为JSON响应,它们需要扩展Flugg\Responder\Exceptions\Http\ApiException
<?php namespace App\Exceptions; use Flugg\Responder\Exceptions\Http\ApiException; class CustomException extends ApiException { /** * The HTTP status code. * * @var int */ protected $statusCode = 400; /** * The error code used for API responses. * * @var string */ protected $errorCode = 'custom_error'; }
您可以通过设置如上所示的$statusCode和$errorCode属性来自定义从您的异常生成的响应。
测试助手
一旦开始转换数据,编写测试来测试数据就变得越来越困难。你可以使用类似Laravel的seeJson或seeJsonEquals的方法,然而,因为数据不会转换(或序列化),所以需要硬编码每个值。
该包提供了一个Flugg\Responder\Traits\MakesApiRequests特质,你可以在tests/TestCase.php文件中使用它,以获取访问一些辅助方法来轻松测试响应。
目前,只有在使用默认序列化器Flugg\Responder\Serializers\ApiSerializer时,成功响应方法才能正常工作。将来你可以使用所有序列化器进行测试。
断言成功响应
测试特质提供了一个seeSuccess()方法,你可以使用它来断言成功响应是成功的
$this->seeSuccess($user, 201);
这会将数据和序列化,就像响应器上的success()方法一样。它将对状态码运行seeStatusCode(),并断言响应具有正确的基结构并包含给定的数据。你也可以传递任何元数据作为第三个参数。
虽然上述方法只检查成功数据中的任何部分是否具有你指定的值,但你也可以断言精确匹配
$this->seeSuccessEquals($user, 201);
这和Laravel的seeJsonEquals几乎一样。
断言错误响应
就像你可以断言成功响应一样,你也可以使用seeError()方法验证你的应用程序是否发送了正确的错误响应
$this->seeError('invalid_user', 400);
这将检查状态码和错误响应结构。你也可以传递一个消息作为第三个参数。
获取成功数据
你也可以轻松地从响应中获取数据
$this->json('post', 'sessions', $credentials); $data = $this->getSuccessData();
这将解码响应JSON,并将数据作为数组返回。
配置
如果你已经按照安装指南中所述发布了供应商资产,你将能够访问一个config/responder.php文件。你可以更改此文件中的值以更改包的运行方式。我们将详细介绍每个配置键。
序列化器类路径
此键表示用于生成成功JSON响应的序列化器类的完整类路径。你可以将其保留为默认的Flugg\Responder\Serializers\ApiSerializer,更改为Fractal的序列化器之一,或者创建一个自定义序列化器。
包含状态码
该包将包括成功和错误响应的状态码。你可以通过将此键设置为false来禁用此功能。
贡献
贡献是受欢迎的,你可以在Github上自由创建一个pull request。你可以使用以下命令运行测试
vendor/bin/phpunit
如果你发现错误或对改进有建议,请自由在Github上提交一个问题。然而,如果这是一个安全问题,请发送电子邮件到flugged@gmail.com。
许可协议
Laravel Responder 是一款免费软件,根据 MIT 许可协议进行分发。更多详细信息,请参阅 license.md。