cubesystems / api-client
API客户端提供了以模块化方式消耗Laravel API的方法。
Requires
- php: 8.0.*
- ext-bcmath: *
- ext-intl: *
- ext-soap: *
- ext-xsl: *
- codedredd/laravel-soap: ^3.0
- illuminate/contracts: ^9.0
- nesbot/carbon: ^2.66
- spatie/laravel-package-tools: ^1.14.0
Requires (Dev)
- barryvdh/laravel-debugbar: ^3.8
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- nunomaduro/collision: ^6
- nunomaduro/larastan: ^2.0.1
- orchestra/testbench: ^7.0
- pestphp/pest: ^1.0
- pestphp/pest-plugin-laravel: ^1.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- spatie/pest-plugin-test-time: ^1.1
README
此包定义了契约并提供这些契约的抽象部分实现。它旨在用作构建高度模块化和可定制的API消耗基础构建块。您可以按需使用其中任何部分。
安装
您可以通过composer安装此包
composer require cubesystems/api-client
配置
要使用Laravel Debugbar集成,请在debugbar.php
配置文件中启用它
return [ ... 'collectors' => [ ... 'api' => true ] ];
创建自定义API客户端实现
首先,让我们定义一些词汇。
SOAP
REST
在此之后,我们可以查看所有接口之间的关系
定义一个端点
为此,我们需要实现CubeSystems\ApiClient\Client\Contracts\Endpoint
契约,这可以通过扩展CubeSystems\ApiClient\Client\AbstractRestEndpoint
或CubeSystems\ApiClient\Client\AbstractSoapEndpoint
类来完成
use CubeSystems\ApiClient\Client\AbstractSoapEndpoint; class MyEndpoint extends AbstractSoapEndpoint {}
定义端点内可访问的服务
为此,我们需要实现CubeSystems\ApiClient\Client\Contracts\Service
契约,这可以通过扩展CubeSystems\ApiClient\Client\AbstractRestService
或CubeSystems\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\Method
由CubeSystems\ApiClient\Client\Methods\AbstractRestMethod
和CubeSystems\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
,则相应的调用将作为缓存层次结构的一部分。这允许通过调用 AbstractMethod
的 removeHierarchyFromCache
方法一次性清除给定层次结构的所有缓存条目。
为此,必须根据您的需求实现 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 中可见
测试
此包使用 Pest 测试框架。您可以使用以下命令运行测试
composer test
变更日志
请参阅 CHANGELOG 了解最近有哪些更改。