利用Laravel中的Guzzle提高代码质量
我是拉威尔的新人,所以请不要太苛刻 我正在构建一个简单的web,它通过Guzzle连接到一个外部API(几个端点),获取一些数据,清理并存储它们 目前,从一个端点来看,我有以下工作:利用Laravel中的Guzzle提高代码质量,laravel,guzzle,Laravel,Guzzle,我是拉威尔的新人,所以请不要太苛刻 我正在构建一个简单的web,它通过Guzzle连接到一个外部API(几个端点),获取一些数据,清理并存储它们 目前,从一个端点来看,我有以下工作: public function handle(Client $client) { try { $request= $client->request('GET', 'https://api.url./something', [ 'heade
public function handle(Client $client)
{
try {
$request= $client->request('GET', 'https://api.url./something', [
'headers' => [
'X-RapidAPI-Key'=> env("FOOTBALL_API_KEY"),
'Accept' => 'application/json'
]
]);
$request = json_decode($request->getBody()->getContents(), true);
foreach ($request as $array=>$val) {
foreach ($val['leagues'] as $id) {
League::firstOrCreate(collect($id)->except(['coverage'])->toArray());
}
}
} catch (GuzzleException $e) {
};
}
因此,我想提出一些代码建议,如何从设计的角度使我的代码更好
我的想法是:
a) 将Guzzle绑定为服务提供商
b) 使用设计模式实现对端点的调用。URI
builder
任何协助都将不胜感激
愿原力与你同在。详细反馈
特定于所提供代码本身的一些指针:
- guzzle客户端
请求
返回的响应与指定给它的参数名称不匹配
- 调用
json\u decode
可能会失败,在这种情况下,它们将返回null
。在防御性编程方面,最好检查那些失败的情况
- 您的案例对回复中的数据进行了一些假设。在使用响应之前,最好检查它是否是您期望的实际格式
- 您捕获了所有异常,但在这些情况下什么也不做。我认为你可以通过以下两种方式来改善这一点:
- 记录异常
- 引发另一个异常,您将在类中捕获该异常,调用
handle()
方法
- 以上两个选项
- 您可以选择注入api键,而不是通过
env()
方法直接获取它。这将防止中描述的问题
一般反馈
感觉您的代码混合了责任,这被认为是不好的做法。handle()
方法现在执行以下操作:
- 发送API请求
- 解码API请求
- 验证API响应
- 解析API响应
- 创建模型
<>你可以考虑把其中的一些或全部移到单独的类中,比如:
ApiClient
负责发送请求
- 负责将响应转换为
\stdClass
ResponseValidator
负责检查响应是否具有预期的数据结构
repsonseparaser
负责将响应\stdClass
转换为集合
LeagueFactory
负责将系列转化为League
型号
有人可能认为前四个类应该放在一个名为ApiClient
的类中。那完全取决于你
所以最后你会想出这样的办法:
<?php
namespace App\Example;
use Psr\Log\LoggerInterface;
class LeagueApiHandler
{
/**
* @var ApiClient
*/
private $apiClient;
/**
* @var ResponseDecoder
*/
private $decoder;
/**
* @var ResponseValidator
*/
private $validator;
/**
* @var ResponseParser
*/
private $parser;
/**
* @var LeagueFactory
*/
private $factory;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(
ApiClient $apiClient,
ResponseDecoder $decoder,
ResponseValidator $validator,
ResponseParser $parser,
LeagueFactory $factory,
LoggerInterface $logger
) {
$this->apiClient = $apiClient;
$this->decoder = $decoder;
$this->validator = $validator;
$this->parser = $parser;
$this->factory = $factory;
$this->logger = $logger;
}
public function handle()
{
try {
$response = $this->apiClient->send();
} catch (\RuntimeException $e) {
$this->logger->error('Unable to send api request', $e->getMessage());
return;
};
try {
$decodedResponse = $this->decoder->decode($response);
} catch (\RuntimeException $e) {
$this->logger->error('Unable to decode api response');
return;
};
if (!$this->validator->isValid($decodedResponse)) {
$this->logger->error('Unable to decode api response');
return;
}
$collections = $this->parser->toCollection($decodedResponse);
foreach ($collections as $collection) {
$this->factory->create($collection);
}
}
}
非常感谢您的反馈,非常感谢。我会处理你的评论。你能给我提供一些材料来研究“如何在laravel中设计代码”吗?我没有任何laravel特定的资料给你,但你可以看看作者写的。他有一些关于干净编码的好主意
namespace App\Example;
use GuzzleHttp\Client;
class ApiClient
{
/**
* @var Client
*/
private $client;
/**
* @var string
*/
private $apiKey;
public function __construct(Client $client, string $apiKey)
{
$this->client = $client;
$this->apiKey = $apiKey;
}
public function send()
{
try {
return $this->client->request('GET', 'https://api.url./something', [
'headers' => [
'X-RapidAPI-Key' => $this->apiKey,
'Accept' => 'application/json'
]
]);
} catch (GuzzleException $e) {
throw new \RuntimeException('Unable to send request to api', 0, $e);
};
}
}
namespace App\Example;
use Psr\Http\Message\ResponseInterface;
class ResponseDecoder
{
public function decode(ResponseInterface $response): \stdClass
{
$response = json_decode($response->getBody()->getContents(), true);
if ($response === null) {
throw new \RuntimeException('Unable to decode api response');
}
return $response;
}
}
namespace App\Example;
class ResponseValidator
{
public function isValid(\stdClass $response): bool
{
if (is_array($response) === false) {
return false;
}
foreach ($response as $array) {
if (!isset($array['leagues'])) {
return false;
}
}
return true;
}
}
namespace App\Example;
use Illuminate\Support\Collection;
class ResponseParser
{
/**
* @param \stdClass $response
* @return Collection[]
*/
public function toCollection(\stdClass $response): array
{
$collections = [];
foreach ($response as $array => $val) {
foreach ($val['leagues'] as $id) {
$collections[] = collect($id)->except(['coverage'])->toArray();
}
}
return $collections;
}
}
namespace App\Example;
use Illuminate\Support\Collection;
class LeagueFactory
{
public function create(Collection $collection): void
{
League::firstOrCreate($collection);
}
}