使用 REST 的最佳设计模式是什么 API
What is the best design pattern to consume REST API
我想在 Laravel(一个 MVC 框架)中使用 Rest API,但我求助于使用 __call
,想知道是否有更好的设计模式。
我知道这是一个糟糕的选择,我正在寻找替代模式,但这是我的存储库 class:
namespace App\Repositories;
use App\Models\OnlinePayment;
use App\Models\Order;
use App\Models\Transaction;
use App\Models\User;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use SoapClient;
class Bank
{
protected $http;
protected $user;
public function __construct()
{
$this->http = new Client;
}
protected function index()
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/report';
$data = [
'user_gender' => $this->user->gender ?? 1,
'user_name' => $this->user->name,
'user_family' => $this->user->family ?? 'خالی',
'user_mobile' => $this->user->mobile,
'user_type' => $this->user->type->name,
];
$options = $this->options($data);
$res = $this->http->request('GET', $url, $options);
$response = json_decode($res->getBody(), true);
return $response;
}
protected function indexData($request)
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers';
$options = $this->options($request->all());
$res = $this->http->request('GET', $url, $options);
$response = response()->json(json_decode($res->getBody(), true), $res->getStatusCode());
return $response;
}
protected function show($national_id)
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers/' . $national_id;
$options = $this->options([]);
$res = $this->http->request('GET', $url, $options);
if ($res->getStatusCode() == 404) {
abort(404);
}
$response = json_decode($res->getBody(), true);
return $response;
}
protected function store($request)
{
$http = new Client;
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers';
$this->user = auth()->user();
$data = array_merge(
[
'customer_national_id' => $request->national_id,
'customer_gender' => $request->gender,
'customer_name' => $request->name,
'customer_family' => $request->family,
'customer_phone' => $request->phone,
'customer_mobile' => $request->mobile,
'customer_city_id' => $request->city_id,
], [
'user_name' => $this->user->nanfig() is a hidden dependency. The settings should also be passed via the construcme,
'user_family' => $this->user->family ?? 'خالی',
'user_mobile' => $this->user->mobile,
'user_type' => $this->user->type->name,
'user_gender' => $this->user->gender ?? 1,
]
);
$res = $http->request('POST', $url, [
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . config('Bank.token'),
],
'json' => $data,
'http_errors' => false
]);
if (! in_array($res->getStatusCode(), [200, 422])) {
$error = ValidationException::withMessages([
'name' => 'خطای ' . $res->getStatusCode() . ' در تعویض کالا'
]);
throw $error;
}
$response = response()->json(json_decode($res->getBody(), true), $res->getStatusCode());
return $response;
}
protected function options($data)
{
$options = [
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . config('Bank.token'),
],
'json' => $data,
'http_errors' => false
];
return $options;
}
public function __call($method, $arguments) {
if (method_exists($this, $method)) {
if (! isset($arguments[0]) || ! $arguments[0] instanceof User) {
$this->user = auth()->user();
} else {
$this->user = $arguments[0];
unset($arguments[0]);
}
return call_user_func_array(array($this, $method), $arguments);
}
}
}
然后在控制器构造函数中创建它的一个实例:
public function __construct()
{
$this->Bank = new Bank();
}
并像这样在控制器中使用它:
$response = $this->Bank->indexData($user, $request);
或者这个:
$response = $this->Bank->indexData($request);
我认为显示的 class 不是 Repository class 因为 Repository 只负责从数据源读取和写入日期。您的 class 做得太多了,违反了所有基本的 MVC 原则。
有些人认为我会修复:
- 存储库不负责创建响应视图数据(如 JSON)
- 存储库不负责创建响应对象
- 存储库独立于 request/response
- 方法名称
index
没有意义,因为存储库不是控制器操作。不要混合模型层和控制器层。
- config() 是一个隐藏的依赖项。这些设置也应该通过构造函数传递。
改为使用更好的分离:
- 创建 class
BankApiClient
- 不要使用像
__call
这样的魔术方法
- 而是使用 public 方法,例如:getUserByNationalId(int $nationalId): UserData
- 等等...
- 让控制器操作使用 BankApiClient 的结果创建/呈现 json 响应。
__call 是 php 的魔法方法,它允许在对象实例之外执行受保护的方法,这是 class 可见性的中断。
如果你想从外部调用一个方法,它必须是public
public function __construct()
{
$this->bank = new Bank()
}
使用自动注入依赖项
public function __construct(Bank $bank)
{
$this->bank = $bank;
}
我想在 Laravel(一个 MVC 框架)中使用 Rest API,但我求助于使用 __call
,想知道是否有更好的设计模式。
我知道这是一个糟糕的选择,我正在寻找替代模式,但这是我的存储库 class:
namespace App\Repositories;
use App\Models\OnlinePayment;
use App\Models\Order;
use App\Models\Transaction;
use App\Models\User;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use SoapClient;
class Bank
{
protected $http;
protected $user;
public function __construct()
{
$this->http = new Client;
}
protected function index()
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/report';
$data = [
'user_gender' => $this->user->gender ?? 1,
'user_name' => $this->user->name,
'user_family' => $this->user->family ?? 'خالی',
'user_mobile' => $this->user->mobile,
'user_type' => $this->user->type->name,
];
$options = $this->options($data);
$res = $this->http->request('GET', $url, $options);
$response = json_decode($res->getBody(), true);
return $response;
}
protected function indexData($request)
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers';
$options = $this->options($request->all());
$res = $this->http->request('GET', $url, $options);
$response = response()->json(json_decode($res->getBody(), true), $res->getStatusCode());
return $response;
}
protected function show($national_id)
{
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers/' . $national_id;
$options = $this->options([]);
$res = $this->http->request('GET', $url, $options);
if ($res->getStatusCode() == 404) {
abort(404);
}
$response = json_decode($res->getBody(), true);
return $response;
}
protected function store($request)
{
$http = new Client;
$url = config('Bank.url') . '/v2/quantum/users/' . $this->user->national_id . '/customers';
$this->user = auth()->user();
$data = array_merge(
[
'customer_national_id' => $request->national_id,
'customer_gender' => $request->gender,
'customer_name' => $request->name,
'customer_family' => $request->family,
'customer_phone' => $request->phone,
'customer_mobile' => $request->mobile,
'customer_city_id' => $request->city_id,
], [
'user_name' => $this->user->nanfig() is a hidden dependency. The settings should also be passed via the construcme,
'user_family' => $this->user->family ?? 'خالی',
'user_mobile' => $this->user->mobile,
'user_type' => $this->user->type->name,
'user_gender' => $this->user->gender ?? 1,
]
);
$res = $http->request('POST', $url, [
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . config('Bank.token'),
],
'json' => $data,
'http_errors' => false
]);
if (! in_array($res->getStatusCode(), [200, 422])) {
$error = ValidationException::withMessages([
'name' => 'خطای ' . $res->getStatusCode() . ' در تعویض کالا'
]);
throw $error;
}
$response = response()->json(json_decode($res->getBody(), true), $res->getStatusCode());
return $response;
}
protected function options($data)
{
$options = [
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . config('Bank.token'),
],
'json' => $data,
'http_errors' => false
];
return $options;
}
public function __call($method, $arguments) {
if (method_exists($this, $method)) {
if (! isset($arguments[0]) || ! $arguments[0] instanceof User) {
$this->user = auth()->user();
} else {
$this->user = $arguments[0];
unset($arguments[0]);
}
return call_user_func_array(array($this, $method), $arguments);
}
}
}
然后在控制器构造函数中创建它的一个实例:
public function __construct()
{
$this->Bank = new Bank();
}
并像这样在控制器中使用它:
$response = $this->Bank->indexData($user, $request);
或者这个:
$response = $this->Bank->indexData($request);
我认为显示的 class 不是 Repository class 因为 Repository 只负责从数据源读取和写入日期。您的 class 做得太多了,违反了所有基本的 MVC 原则。
有些人认为我会修复:
- 存储库不负责创建响应视图数据(如 JSON)
- 存储库不负责创建响应对象
- 存储库独立于 request/response
- 方法名称
index
没有意义,因为存储库不是控制器操作。不要混合模型层和控制器层。 - config() 是一个隐藏的依赖项。这些设置也应该通过构造函数传递。
改为使用更好的分离:
- 创建 class
BankApiClient
- 不要使用像
__call
这样的魔术方法
- 而是使用 public 方法,例如:getUserByNationalId(int $nationalId): UserData
- 等等...
- 让控制器操作使用 BankApiClient 的结果创建/呈现 json 响应。
__call 是 php 的魔法方法,它允许在对象实例之外执行受保护的方法,这是 class 可见性的中断。
如果你想从外部调用一个方法,它必须是public
public function __construct()
{
$this->bank = new Bank()
}
使用自动注入依赖项
public function __construct(Bank $bank)
{
$this->bank = $bank;
}