Installation
composer require carloschininin/api-bundle
Add to config/app.php under providers:
CarlosChininin\ApiBundle\ApiServiceProvider::class,
Publish the config (if available):
php artisan vendor:publish --provider="CarlosChininin\ApiBundle\ApiServiceProvider"
First Use Case: Basic API Request
Register a new API client in config/api.php:
'clients' => [
'example' => [
'base_uri' => 'https://api.example.com',
'timeout' => 30,
],
],
Use the facade in a controller or service:
use CarlosChininin\ApiBundle\Facades\Api;
$response = Api::client('example')->get('/endpoint');
$data = $response->json();
Key Files to Review
config/api.php (configuration)src/Facades/Api.php (facade usage)src/ApiServiceProvider.php (service registration)Request/Response Handling Use the facade for HTTP methods:
$response = Api::client('example')->post('/users', ['name' => 'John']);
$response->status(); // 201
$response->json(); // Decoded JSON
Authentication Attach auth headers globally in config:
'clients' => [
'authenticated' => [
'base_uri' => 'https://api.example.com',
'headers' => [
'Authorization' => 'Bearer token123',
],
],
],
Or dynamically:
Api::client('example')->withHeaders(['X-API-Key' => 'secret'])->get('/secure');
Error Handling Use middleware or exceptions:
try {
$response = Api::client('example')->get('/fail');
} catch (\CarlosChininin\ApiBundle\Exceptions\ApiException $e) {
Log::error($e->getMessage());
}
Integration with Laravel Services Bind the client to a service container:
$this->app->bind('api.example', function ($app) {
return Api::client('example');
});
Inject into controllers:
public function __construct(\CarlosChininin\ApiBundle\ApiClient $client) {
$this->client = $client;
}
Testing Mock the facade in tests:
Api::shouldReceive('client')->andReturn($mockClient);
No Built-in Retry Logic
$retry = 3;
while ($retry--) {
try {
$response = Api::client('example')->get('/endpoint');
break;
} catch (\Exception $e) {
if ($retry === 0) throw $e;
sleep(1);
}
}
Config Overrides
config/api.php is published and merged correctly. Use php artisan config:clear if changes aren’t reflected.Facade vs. Direct Client
// Bad: Facade in constructor
public function __construct() {
$this->client = Api::client('example'); // Tight coupling
}
// Good: Inject interface
public function __construct(ApiClientInterface $client) { ... }
No Built-in Rate Limiting
throttle middleware or implement custom logic:
$response = Api::client('example')
->withMiddleware(new \CarlosChininin\ApiBundle\Middleware\RateLimit())
->get('/rate-limited');
Custom Clients Extend the base client for domain-specific logic:
namespace App\Services;
use CarlosChininin\ApiBundle\ApiClient;
class StripeClient extends ApiClient {
public function createCustomer(array $data) {
return $this->post('/customers', $data);
}
}
Logging Enable request/response logging in config:
'logging' => true,
Or use middleware:
Api::client('example')->withMiddleware(new \CarlosChininin\ApiBundle\Middleware\Log());
Environment-Specific Config Use Laravel’s config caching:
php artisan config:cache
Override values in .env:
API_EXAMPLE_BASE_URI=https://staging.example.com
Debugging
dd(Api::client('example')->get('/debug')->getBody());
Performance
$client = Api::client('example'); // Reuse across requests
How can I help you explore Laravel packages today?