Installation Add the package via Composer:
composer require corey-mac/api-extension
Publish the config (if needed):
php artisan vendor:publish --provider="CoreyMac\ApiExtension\ApiExtensionServiceProvider"
Basic Setup
Register the API extension in your AppServiceProvider or a dedicated service provider:
use CoreyMac\ApiExtension\ApiExtension;
public function register()
{
$this->app->singleton(ApiExtension::class, function ($app) {
return new ApiExtension(config('api-extension'));
});
}
First Use Case: Extending API Responses
Use the ApiExtension facade to modify responses globally:
use CoreyMac\ApiExtension\Facades\ApiExtension;
ApiExtension::extend(function ($response) {
$response->setData([
'meta' => [
'timestamp' => now()->toDateTimeString(),
],
]);
});
Leverage the package to standardize API responses across controllers:
// In a controller or middleware
ApiExtension::extend(function ($response) {
$response->setData([
'pagination' => $response->getData('data.pagination', []),
'links' => [
'next' => route('api.v1.users.index', ['page' => $response->getData('data.current_page') + 1]),
],
]);
});
Use middleware to apply extensions dynamically:
use CoreyMac\ApiExtension\Facades\ApiExtension;
class ApiResponseMiddleware extends Middleware
{
public function handle($request, Closure $next)
{
ApiExtension::extend(function ($response) {
$response->setData([
'user' => auth()->user(),
]);
});
return $next($request);
}
}
Apply extensions based on request context (e.g., route, user role):
ApiExtension::extendIf(function ($response) {
return request()->routeIs('api.v1.admin.*');
}, function ($response) {
$response->setData([
'admin_mode' => true,
]);
});
Extend the base ApiResponse class for project-specific needs:
use CoreyMac\ApiExtension\ApiResponse;
class CustomApiResponse extends ApiResponse
{
public function addCustomMeta($key, $value)
{
$this->setData(['meta' => [$key => $value]]);
}
}
Use the package to differentiate responses by API version:
ApiExtension::extendForVersion('v2', function ($response) {
$response->setData([
'version' => '2.0',
]);
});
Overriding Default Behavior The package modifies responses globally. Ensure extensions don’t conflict with existing logic (e.g., Laravel’s default JSON responses). Test with:
return ApiExtension::response()->setData(['test' => true]);
Performance Impact Avoid heavy computations in extensions. Cache or lazy-load data where possible.
Middleware Order
Register middleware after ApiExtension is bound to the container to ensure proper execution order.
Config Overrides
The package relies on config('api-extension'). Ensure your config file exists and is properly structured:
return [
'default_version' => 'v1',
'extensions' => [],
];
Check Extensions Log extensions to verify they’re applied:
ApiExtension::extend(function ($response) {
\Log::debug('Extension applied:', $response->getData());
});
Inspect Response Dump the final response in a middleware:
\Log::debug('Final API Response:', $response->getData());
Disable Extensions Temporarily
Use ApiExtension::disable() in testing or debugging:
ApiExtension::disable();
Custom Response Formats
Override the ApiResponse class and bind it in the service provider:
$this->app->bind(ApiResponse::class, CustomApiResponse::class);
Dynamic Extension Loading Load extensions from a database or config file:
$extensions = config('api-extension.dynamic_extensions');
foreach ($extensions as $extension) {
ApiExtension::extend($extension['callback']);
}
Event-Based Extensions
Trigger extensions via Laravel events (e.g., Illuminate\Http\After):
event(new After($request, $response));
ApiExtension::extend(function ($response) use ($request) {
// Logic based on the event
});
Testing
Mock the ApiExtension facade in tests:
$this->partialMock(ApiExtension::class, function ($mock) {
$mock->shouldReceive('extend')->once();
});
How can I help you explore Laravel packages today?