bsll/api-bundle
Laravel bundle for building and organizing JSON API endpoints, with helpers for routing, request/response handling, and common API concerns. A lightweight starting point for integrating an API layer into an existing app or new project.
Installation Add the package via Composer:
composer require bsll/api-bundle
Publish the bundle’s configuration (if available):
php artisan vendor:publish --provider="Bsll\ApiBundle\ApiServiceProvider"
Service Provider
Ensure the ApiServiceProvider is registered in config/app.php under providers:
Bsll\ApiBundle\ApiServiceProvider::class,
First Use Case: Basic API Request Inject the API client into a controller or service:
use Bsll\ApiBundle\Contracts\ApiClientInterface;
class ExampleController extends Controller
{
public function __construct(private ApiClientInterface $apiClient) {}
public function fetchData()
{
$response = $this->apiClient->get('endpoint');
return response()->json($response);
}
}
Configuration
Check config/api.php (if published) for default settings like base URI, headers, or authentication.
Pass credentials via the client or config:
$this->apiClient->withAuth('token')->get('protected-endpoint');
Or configure globally in config/api.php:
'auth' => [
'token' => env('API_TOKEN'),
'type' => 'bearer',
],
Use middleware or decorators to modify requests/responses:
$this->apiClient->withMiddleware(new CustomRequestTransformer())->post('data', $payload);
Configure retry logic in the client:
$this->apiClient->withRetry(3, 500)->get('unstable-endpoint');
Listen for API events (if supported) to log or transform data:
event(new \Bsll\ApiBundle\Events\ApiRequestEvent($request));
Mock the ApiClientInterface in tests:
$mock = Mockery::mock(ApiClientInterface::class);
$mock->shouldReceive('get')->andReturn(['data' => 'test']);
$this->app->instance(ApiClientInterface::class, $mock);
Laravel HTTP Client Bridge If the bundle supports it, integrate with Laravel’s built-in HTTP client for consistency:
$this->apiClient->useHttpClient(app(\Illuminate\Http\Client\PendingRequest::class));
API Versioning Use route middleware to switch API versions dynamically:
Route::middleware(['api-version:v2'])->group(function () {
// Routes using v2 of the API
});
Caching Responses Cache API responses with Laravel’s cache system:
$response = Cache::remember('api_data', now()->addHours(1), function () {
return $this->apiClient->get('data');
});
No Official Documentation
src/ for undocumented features or behaviors.description.md or README.md for hidden gems (e.g., default config keys).Dependency Conflicts
Global State Risks
ApiClient::getInstance().Error Handling
try {
$response = $this->apiClient->get('endpoint');
} catch (\Bsll\ApiBundle\Exceptions\ApiException $e) {
Log::error($e->getMessage());
}
Network Timeouts
$this->apiClient->withTimeout(30)->get('slow-endpoint');
Enable Guzzle Debugging If the bundle uses Guzzle, enable debug mode:
$this->apiClient->withDebug(true); // Check if supported
Or use Laravel’s logging:
\Log::debug('API Request', ['request' => $request->toArray()]);
Inspect Raw Responses Dump responses to debug unexpected data:
dd($this->apiClient->get('endpoint')->getBody());
Check for Middleware Conflicts Disable middleware temporarily to isolate issues:
$this->apiClient->withoutMiddleware(CustomMiddleware::class);
Custom Clients Extend the base client for domain-specific logic:
class CustomApiClient extends \Bsll\ApiBundle\ApiClient
{
public function customMethod()
{
return $this->post('custom', ['key' => 'value']);
}
}
Add New HTTP Methods
If the bundle lacks a method (e.g., PATCH), extend the client:
class ExtendedApiClient extends ApiClient
{
public function patch($uri, array $data = [])
{
return $this->request('PATCH', $uri, ['body' => $data]);
}
}
Plugin System If the bundle supports plugins, create one to add functionality:
class LoggingPlugin implements \Bsll\ApiBundle\Contracts\ApiPlugin
{
public function handle($request)
{
Log::info('API Call', ['uri' => $request->getUri()]);
return $request;
}
}
Service Provider Overrides
Bind custom implementations in your AppServiceProvider:
$this->app->bind(
\Bsll\ApiBundle\Contracts\ApiClientInterface::class,
\App\Services\CustomApiClient::class
);
Default Config Location
The bundle may not publish config by default. Manually create config/api.php:
return [
'base_uri' => env('API_BASE_URI', 'https://api.example.com'),
'timeout' => 10,
];
Environment Variables
Prefix API-related env vars clearly (e.g., API_*):
API_BASE_URI=https://api.example.com
API_TOKEN=your_token_here
Fallback Behavior Test edge cases like:
How can I help you explore Laravel packages today?