cubesystems/api-client

API客户端提供了以模块化方式消耗Laravel API的方法。

v3.0.0 2024-02-06 01:41 UTC

This package is auto-updated.

Last update: 2024-09-06 03:00:40 UTC


README

此包定义了契约并提供这些契约的抽象部分实现。它旨在用作构建高度模块化和可定制的API消耗基础构建块。您可以按需使用其中任何部分。

安装

您可以通过composer安装此包

composer require cubesystems/api-client

配置

要使用Laravel Debugbar集成,请在debugbar.php配置文件中启用它

return [
    ...
    'collectors' => [
        ...
        'api' => true
    ]
];

创建自定义API客户端实现

首先,让我们定义一些词汇。

SOAP

方法 vs 服务 vs 端点 方法、服务和端点

REST

方法 vs 服务 vs 端点 方法、服务和端点

在此之后,我们可以查看所有接口之间的关系

接口 主要接口之间的关系

定义一个端点

为此,我们需要实现CubeSystems\ApiClient\Client\Contracts\Endpoint契约,这可以通过扩展CubeSystems\ApiClient\Client\AbstractRestEndpointCubeSystems\ApiClient\Client\AbstractSoapEndpoint类来完成

use CubeSystems\ApiClient\Client\AbstractSoapEndpoint;

class MyEndpoint extends AbstractSoapEndpoint {}

定义端点内可访问的服务

为此,我们需要实现CubeSystems\ApiClient\Client\Contracts\Service契约,这可以通过扩展CubeSystems\ApiClient\Client\AbstractRestServiceCubeSystems\ApiClient\Client\AbstractSoapService类来完成

use CubeSystems\ApiClient\Client\AbstractSoapService;

class MyService extends AbstractSoapService
{
    protected const SERVICE_PATH = 'path/to/service';
}

创建一个请求负载类

这可以通过直接实现CubeSystems\ApiClient\Client\Contracts\Payload契约或通过扩展CubeSystems\ApiClient\Client\Payloads\AbstractPayload类来完成

use CubeSystems\ApiClient\Client\Payloads\AbstractPayload;

class MyPayload extends AbstractPayload
{
    private string $parameter;

    public function setId(string $id): MyPayload
    {
        $this->id = $id;

        return $this;
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id
        ];
    }

    public function getCacheKey(): string
    {
        return self::class . $this->id;
    }
}

创建一个响应类

这可以通过直接实现CubeSystems\ApiClient\Client\Contracts\Response契约或通过扩展CubeSystems\ApiClient\Client\Responses\AbstractResponse类来完成

use CubeSystems\ApiClient\Client\Responses\AbstractResponse;

class MyResponse extends AbstractResponse
{
    private MyDto $myDto;

    public function getMyDto(): MyDto
    {
        return $this->myDto;
    }

    public function setMyDto(MyDto $myDto): MyResponse
    {
        $this->myDto = $myDto;

        return $this;
    }
}

为服务创建一个方法

CubeSystems\ApiClient\Client\Contracts\MethodCubeSystems\ApiClient\Client\Methods\AbstractRestMethodCubeSystems\ApiClient\Client\Methods\AbstractSoapMethod类实现。

use CubeSystems\ApiClient\Client\Methods\AbstractSoapMethod;
use CubeSystems\ApiClient\Client\Plugs\PlugManager;
use CubeSystems\ApiClient\Client\Strategies\NeverCacheStrategy;
use Illuminate\Support\Arr;

class MyMethod extends AbstractSoapMethod
{
    protected const METHOD_NAME = 'MyMethod';

    public function __construct(
        MyService $service,
        NeverCacheStrategy $cacheStrategy,
        PlugManager $plugManager,
    ) {
        parent::__construct($service, $cacheStrategy, $plugManager);
    }
    
    protected function toResponse(array $rawResponse, int $httpCode): MyResponse
    {
        $response = new MyResponse();
        ...
        $myDto = new MyDto();
        $myDto->setName(Arr::get($rawResponse, 'name'));
        $myDto->setAge((int) Arr::get($rawResponse, 'age'));
        $response->setDto($myDto);
        
        return $response;
    }
}

调用API

完成所有这些后,您可以使用以下方式进行调用

use Foo\Endpoints\MyEndpoint;
use Foo\Services\MyService;
use Foo\Methods\MyMethod;
use Foo\Payloads\MyPayload;

class MyRepository
{
    public function getMyDtoById(string $id): MyDto
    {
        $myEndpoint = new MyEndpoint(config('api-client.endpoints.myEndpoint.url'));
        $myService = new MyService($myEndpoint, collect(), collect(), new ApiClient());
        $myMethod = new MyMethod($myService, new NeverCacheStrategy());
        $myPayload = new MyPayload();
        $myPayload->setId($id);
        
        return $myMethod->call($myPayload)->getMyDto();
    }
}

或者利用Laravel完成的依赖注入。

扩展CubeSystems\ApiClient\ApiClientServiceProvider类并注册您的绑定

public function register(): void
{
    parent::register();
    
    $this->app->singleton(MyEndpoint::class, function (Application $app) {
        $url = config('api-client.endpoints.myEndpoint.url');

        return new MyEndpoint($url);
    });
}

现在可以更简洁地完成相同的事情

use Foo\Methods\MyMethod;
use Foo\Payloads\MyPayload;

class MyRepository
{
    public function getMyDtoById(string $id): MyDto
    {
        $myMethod = app(MyMethod::class);
        $myPayload = new MyPayload();
        $myPayload->setId($id);
        
        return $myMethod->call($myPayload)->getMyDto();
    }
}

查看测试以获取更多示例。

缓存

AbstractMethod类包含一个缓存机制。只需将所需的缓存策略传递给构造函数即可。有3种策略可用

  • CubeSystems\ApiClient\Client\Cache\NeverCacheStrategy - 永不缓存响应
  • CubeSystems\ApiClient\Client\Cache\RequestCacheStrategy - 在请求期间缓存响应
  • CubeSystems\ApiClient\Client\Cache\TimeIntervalCacheStrategy - 在给定时间间隔内缓存响应

您还可以通过实现CubeSystems\ApiClient\Client\Contracts\CacheStrategy契约来创建自己的策略。

CubeSystems\ApiClient\Client\Contracts\Payload::getCacheKey() 方法用于判断给定负载是否存在有效的缓存条目。如果存在,则从缓存中检索响应。否则,调用远程API。

分层缓存

如果负载从 isUsingCacheHierarchy 方法返回 true,则相应的调用将作为缓存层次结构的一部分。这允许通过调用 AbstractMethodremoveHierarchyFromCache 方法一次性清除给定层次结构的所有缓存条目。

为此,必须根据您的需求实现 CubeSystems\ApiClient\Client\Contracts\Payload::getCacheHierarchyKey 方法。

此外,AbstractPayload 现在接受可选的 CachePrefix 参数,可以用来区分相同 类型 的方法和负载的缓存层次结构。典型的用例是区分不同用户的缓存层次结构。

还有更多

事件

CubeSystems\ApiClient\Client\Methods\AbstractMethod 类触发以下事件

  • CubeSystems\ApiClient\Events\ApiCalled - 在调用远程API之后
  • CubeSystems\ApiClient\Events\ResponseRetrievedFromCache - 在从缓存中检索响应而未调用远程API之后

您可以监听这些事件并执行一些附加操作,如记录。

Laravel Debugbar 集成

如果按照上述描述将 debugbar.collectors.api 配置选项设置为 true,则所有API调用(和缓存检索)将在 Laravel Debugbar 中可见

Debugbar integration Debugbar 集成

测试

此包使用 Pest 测试框架。您可以使用以下命令运行测试

composer test

变更日志

请参阅 CHANGELOG 了解最近有哪些更改。