composer require yansongda/artful:~1.1.0
config/artful.php):
return [
'http' => [
'timeout' => 30.0,
'base_uri' => 'https://api.example.com',
],
'clients' => [
'default' => [
'plugins' => [],
],
],
];
use Yansongda\Artful\Artful;
use Yansongda\Artful\ArtfulManager;
public function register()
{
$this->app->singleton(ArtfulManager::class, function ($app) {
return new ArtfulManager($app['config']['artful']);
});
}
public function boot()
{
$response = Artful::client('default')->get('/users');
$data = $response->toArray();
}
Replace a Guzzle-based payment gateway call:
// Before (Guzzle)
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.stripe.com/payments', [
'json' => ['amount' => 100],
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
// After (Artful)
$response = Artful::client('stripe')->post('/payments', [
'json' => ['amount' => 100],
]);
Pattern: One file per API service with isolated configurations.
// config/artful.php
return [
'clients' => [
'stripe' => [
'base_uri' => 'https://api.stripe.com/v1',
'plugins' => [
\Yansongda\Artful\Plugin\AuthPlugin::class,
],
'auth' => [
'type' => 'bearer',
'token' => env('STRIPE_TOKEN'),
],
],
'shopify' => [
'base_uri' => 'https://{shop}.myshopify.com/admin/api/2023-07',
'plugins' => [
\App\Plugins\ShopifyHeaderPlugin::class,
],
],
],
];
Pattern: Extend functionality without modifying core logic.
// app/Plugins/CustomHeaderPlugin.php
namespace App\Plugins;
use Yansongda\Artful\Plugin\AbstractPlugin;
use Psr\Http\Message\RequestInterface;
class CustomHeaderPlugin extends AbstractPlugin
{
public function handle(RequestInterface $request)
{
return $request->withHeader('X-Custom-Header', 'value');
}
}
// Usage in config/artful.php
'clients' => [
'analytics' => [
'plugins' => [
\App\Plugins\CustomHeaderPlugin::class,
],
],
],
Pattern: Trigger actions on request/response lifecycle.
// Listen to response events
Artful::event()->listen(\Yansongda\Artful\Event\RequestStarted::class, function ($event) {
\Log::info('API request started', ['url' => $event->getRequest()->getUri()]);
});
// Listen to response events
Artful::event()->listen(\Yansongda\Artful\Event\ResponseReceived::class, function ($event) {
if ($event->getResponse()->getStatusCode() >= 400) {
\Log::error('API request failed', [
'status' => $event->getResponse()->getStatusCode(),
'body' => $event->getResponse()->getBody(),
]);
}
});
Pattern: Non-blocking API calls for high-performance scenarios.
// Enable Swoole in config/artful.php
'http' => [
'factory' => \Yansongda\Artful\SwooleHttpFactory::class,
],
// Async request
$response = Artful::client('swoole')->getAsync('/data')->wait();
Pattern: Bind Artful to Laravel’s service container.
// app/Providers/ArtfulServiceProvider.php
public function register()
{
$this->app->singleton(\Yansongda\Artful\ArtfulManager::class, function ($app) {
$manager = new ArtfulManager($app['config']['artful']);
$manager->setEventDispatcher($app->make(\Yansongda\Artful\Event\EventDispatcher::class));
return $manager;
});
$this->app->alias(\Yansongda\Artful\Artful::class, \Yansongda\Artful\ArtfulManager::class);
}
Pattern: Override configurations per request.
$response = Artful::client('default')
->withConfig(['timeout' => 60.0])
->get('/slow-endpoint');
Config Key Changes:
httpFactory was renamed to http in v1.1.0.config/artful.php if upgrading from older versions.
// Old (v1.0.x)
'httpFactory' => \Yansongda\Artful\Http\GuzzleHttpFactory::class,
// New (v1.1.0+)
'http' => \Yansongda\Artful\Http\GuzzleHttpFactory::class,
Plugin Execution Order:
Plugin\PriorityPlugin to enforce execution order.
'plugins' => [
\App\Plugins\AuthPlugin::class,
\App\Plugins\LoggingPlugin::class,
],
Swoole Compatibility:
// Disable Swoole for specific clients
'clients' => [
'swoole_client' => [
'http' => \Yansongda\Artful\Http\GuzzleHttpFactory::class, // Force Guzzle
],
],
PSR-7 Message Handling:
Illuminate\Http\Request.$psr7Request = Artful::client()->createRequest('GET', '/users');
$laravelRequest = new \Illuminate\Http\Request(
$psr7Request->getMethod(),
$psr7Request->getUri(),
$psr7Request->getHeaders(),
[],
[],
$psr7Request->getBody()
);
Event Dispatcher Conflicts:
$dispatcher = new \Yansongda\Artful\Event\LaravelEventDispatcher($this->app['events']);
Artful::event()->setDispatcher($dispatcher);
Empty Packer Handling:
JsonPacker may throw errors if no packer is set.config/artful.php includes a default packer:
'packer' => \Yansongda\Artful\Packer\JsonPacker::class,
Enable Verbose Logging:
Artful::client()->setDebug(true);
Check logs for raw request/response details.
Inspect Plugins:
Use Artful::client()->getPlugins() to list active plugins and their order.
Mock HTTP Calls: Replace the HTTP factory in tests:
$manager = new ArtfulManager($config);
$manager->setHttpFactory(new \Yansongda\Artful\Http\MockHttpFactory());
Validate PSR Compliance:
Use phpstan to ensure PSR-7/11 compliance:
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse --level=5
Yansongda\Artful\Http\HttpFactoryInterface for non-Guzzle/Swoole clients (e.g., cURL).
class CustomHttpFactory implements HttpFactoryInterface
How can I help you explore Laravel packages today?