-
-
Notifications
You must be signed in to change notification settings - Fork 935
Description
API Platform version(s) affected: 4.1.25
Description
When using API Platform’s Laravel integration, custom error handler callbacks defined in bootstrap/app.php (e.g. via $exceptions->respond() or $exceptions->render()) are ignored because the deferred provider replaces the default error handler with its own decorated handler before the callbacks are even registered.
In the DeferredProvider, API Platform decorates the default error handler with its own (ApiPlatform\Laravel\Exception\ErrorHandler). Inside the render() method, it checks whether the request is an API Platform operation. If not, it delegates handling to the decorated service or the parent class:
$apiOperation = $this->initializeOperation($request); if (!$apiOperation) { return $this->decorated ? $this->decorated->render($request, $exception) : parent::render($request, $exception); }
Because the deferred provider registers its bindings before the custom render/respond callbacks are registered, it extends and decorates the default error handler that contains null callbacks. When its time to check if there are any custom render/respond callbacks, because we decorated a handler that never had them set, we don't have anything to run.
Impact
- Custom
$exceptions->render()or$exceptions->respond()definitions are never called. - Developers cannot override exception handling when API Platform’s deferred provider is registered.
Proposed Solution
To restore expected behavior, the handler could directly call parent::render() instead of delegating to $this->decorated->render() when $apiOperation is false. This ensures Laravel’s exception handling pipeline (including user-defined callbacks) is respected. We may also try registering the APIP exception handler if the non-deferred provider. I have not tried this solution but it may be an option.
References
- Source:
ApiPlatform\Laravel\Exception\ErrorHandler - Affected: API Platform Laravel integration (DeferredProvider)
How to reproduce : Attempt to define your own render/respond callbacks in the bootstrap/app.php file and they fail to run.
If you dd() out the decorated handler, you'll noticed, even if you have defined your own callbacks, they have not been registered yet:
bootstrap/app.php:
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->respond(function (Response $response, Throwable $exception, Request $request) {
...
ApiPlatformDeferredProvider.php Line 258:
$this->app->extend(
ExceptionHandler::class,
function (ExceptionHandler $decorated, Application $app) {
dd($decorated);
/** @var ConfigRepository */
$config = $app['config'];
....
Output:
Illuminate\Foundation\Exceptions\Handler {#3084 ▼
#container: Illuminate\Foundation\Application {[#11 ▶](https://mi.test/asd#sf-dump-1026641604-ref211)}
#dontReport: []
#dontReportCallbacks: []
#reportCallbacks: []
#levels: []
#throttleCallbacks: []
#contextCallbacks: []
#renderCallbacks: []
#shouldRenderJsonWhenCallback: null
#finalizeResponseCallback: null
#exceptionMap: []
#hashThrottleKeys: true
#internalDontReport: array:12 [▶]
#dontFlash: array:3 [▶]
#withoutDuplicates: false
#reportedExceptionMap: WeakMap {#2898}
}
You'll notice finalizeResponseCallback is null, but this should be the registered respond() callback.
Additional Context
Happy to submit a PR - just need to know which direction the team would like to take.