我正在制作一个REST API,它将根据进行调用的用户类型返回不同的JSON响应。
有一个端点:example.com/api/v1/collect
使用 Laravel 的 API 身份验证来获取具有$user = auth()->guard('api')->user();
的用户模型。
每个User
将属于一个Type
。
如果User 1
(type_id 1) 进行调用,响应将如下所示:
{
"example": 1,
"success": true,
"data" : [
...
]
}
如果User 2
(type_id 2) 进行调用,则响应可能会有所不同,具体取决于用户的类型。它可能看起来像:
{
"example": 2,
"response" : [
...
],
"custom": "string",
"success": 200
}
...
是我们发回的数据(例如帖子标题列表),它将始终相同,但它周围的"信封"(或包装器)将特定于每个用户(或用户类型)。
到目前为止,我找到了两种解决方案,以抽象的方式包装该...
:
解决方案1:使用拉拉维尔刀片
// ApiV1ApiController.php
$data = $user->posts->pluck('title');
// Each type of user will have a different blade filename
// There could be around a 100 types which will result in a 100 blade files
// The filename is stored in the database
$filename = $user->type->filename; // returns 'customBladeTemplate'
// Return a JSON response after passing the $data to the view
return response()->json([
view($filename, compact('data'))->render(),
]);
为每种类型的用户使用刀片文件允许我像这样包装数据:
// resources/views/customBladeTemplate.blade.php
// This filename has to match the one in the database column
{
"example": 1,
"success": true,
"data" : [
{!! $data !!}
]
}
这将输出用户 1 的 JSON 响应(示例 1)
解决方案 2:使用 Laravel 响应宏
// ApiV1ApiController.php
$data = $user->posts->pluck('title');
// Each type of user will have a different macro name
// There could be around a 100 types which will result in a 100 different macros
// The macro name is stored in the database
$macroName = $user->type->macro_name; // returns 'customMacroName'
return response()->{macroName}($data);
使用数据库中的宏名称为每种类型的用户创建一个宏:
// AppProvidersAppServiceProvider.php
use IlluminateHttpResponse;
public function boot()
{
Response::macro('customMacroName', function ($data) {
return Response::json([
'example' => 2,
'response' => $data,
'custom' => 'string',
'success' => 200,
]);
});
}
该宏将为用户 2 输出 JSON 响应(示例 2)
两种选择都很好用,但我仍然想知道:
- 有没有另一种(可能更好)的方法可以做到这一点?
- 这两种解决方案是否有效,或者是否可以增强?
- 这两种解决方案中哪一种似乎更好,为什么?
编辑:$data
实际上不是来自雄辩的模型,而是来自序列化的JSON列(JSON强制转换) - 这意味着我无法使用LaravelAPI资源
如果您正在寻找响应格式,则应使用Laravel API Resources
根据您的要求(两种类型的用户的数据格式不同),您可以创建两个不同的 API 资源类。
AdminResource
UserResource
.
在这里,您在控制字段或组织数据方面具有更多的灵活性。
下面介绍了如何定义资源类:
<?php
namespace AppHttpResources;
use IlluminateHttpResourcesJsonResource;
class UserResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param IlluminateHttpRequest
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
您可以将其用作:
use AppUser;
use AppHttpResourcesUserResource;
Route::get('/user', function () {
return new UserResource(User::find(1));
});
如果要将条件签入包含在用户类型中,可以创建一个名为renderJson($userType, $data)
的通用函数并将其放在父类中,也可以用 traits 包装,这一切都取决于您的应用程序体系结构。
在这里,您可以找到 API 资源:https://laravel.com/docs/5.8/eloquent-resources 的 laravel 文档
编辑:
使用Laravel API 资源,您不仅可以解析模态对象,还可以解析任何可数组对象。
从本质上讲,它们只是具有一项非常重要工作的简单对象 做 — 转换你的对象(有趣的是我说的是对象而不是 模型)。要开箱即用,您所要做的就是实例化 具有可阵列对象的资源(集合或个人)。如果 您没有执行任何其他操作,只是生成了一个标准资源并传入了一个 可数组对象 资源将转换该对象 自动,因为模型是可阵列的,这就是我得到的地方 因为如果您创建资源集合并实例化 它带有一组模型,然后模型到达数组而不是 他们相应的资源。 来源:https://medium.com/@dinotedesco/laravel-api-resources-what-if-you-want-to-manipulate-your-models-before-transformation-8982846ad22c
因此,在您的情况下,如果您只需collect()
json 数据并传递给 api 资源。
您可以使用中间件来更改响应的外观。
使用中间件,您可以在执行常规代码后更改响应,而无需在控制器本身中考虑这一点。使用以下代码,您可以在执行响应后对其进行修改。
<?php
namespace AppHttpMiddleware;
use Closure;
class AfterMiddleware
{
public function handle($request, Closure $next)
{
// Calls the controller and processes the request.
$response = $next($request);
// Here you can retrieve the user and modify the response however you want.
// Some example code:
$user = Auth::user();
if ($user->type == 1) {
... //Change response for user type 1
}
if ($user->type == 2) {
... //Change response for user type 2
}
// Etc...
return $response;
}
}
参考: https://laravel.com/docs/5.8/middleware
取决于响应之间的差异。 我倾向于清点每种类型的共同特征,并根据需要构建响应数组。 这可以在控制器或帮助程序函数中完成,然后使用 Laravel 的 JSON 响应类型返回。
$response = [];
// results common to all types
$response['example'] = $example;
$response['success'] = $success;
// customized results for specific types
if (in_array($type, [1, 3, 4, 5, ...])) {
$response['data'] = $dotdotdot;
}
if (in_array($type, [2, 6, 7, 8, ...])) {
$response['response'] = $dotdotdot;
$response['custom'] = $custom;
}
return response()->json($response);
我不知道这是否是你要找的。几个月前我有类似的东西,并使用json文件修复了它。由于 json 非常快,您可以创建数千种类型。
对不起,我的英语不好,我会在周末后修复它:-)
让我们开始吧。
首先,用户使用拉拉维尔护照或 api 路由登录。 其次,API 调用控制器。(类)。我将根据您的信息创建一个类。
假设 API 调用ApiController
,方法handle
use IlluminateHttpRequest;
class ApiController
{
public function __construct()
{
}
/**
* Handle the incoming request
*
* @param Request $request
*/
public function handle(Request $request)
{
//first let's find the correct format
$type = $requets->user()->type; //lets say type_1
$config = $this->getUserType($type);
//i don't know where you data comes from but let's say $data is your data.
$data = json_encode(['some' => "data", 'to' => "return"]);
//lets fill the data
$response = $this->fillDataInConfig($data, $config);
return response()->json($response);
}
/**
* Find the user type config by type name
*
* @param string $type
* @return object
*/
private function getUserType(string $type) : string
{
//let store them in the local storage
$config = Storage::disk('local')->get("api_types/$type.json");
return json_decode($config);
}
/**
* Fill the data
*
* @param mixed $data
* @param object $config
* @return object
*/
private function fillDataInConfig($data, object $config) : object
{
//as for your example. The reusl//
// {
// "example": 2,
// "response" : *responseData*, <===== where the response should be
// "custom": "string",
// "success": 200
// }
foreach($config as $index => $value){
if($value === '*responseData*'){
$config->{$idnex} = $data;
}
}
//the data is filled in the response index
return $config;
}
}