Throughout Craft's controllers, anywhere that returns JSON with errors, the response is a 200.
It really should be 4xx or 5xx, so it can be properly handled.
A good solution might be to add this to craft\web\Controller::asErrorJson
, and use that more universally.
I'm thinking something like this might be ideal:
public function asErrorJson($data, int $statusCode = 500): YiiResponse
{
$data = is_string($data) ? ['error' => $error] : $data;
return $this->asJson($data)
->setStatusCode($statusCode);
}
Or perhaps something else to unify all JSON responses (success, error, errors, message, etc: https://github.com/craftcms/cms/issues/2495)
Agree this would be better. However it would be a breaking change for anyone creating these requests using jQuery Ajax methods, as the success
method would no longer be called on non-200 responses. (An improvement to be sure but will have to wait until Craft 4.)
Thanks @brandonkelly.
In the meantime I wonder if I can duck-punch craft\web\Controller
with an override of asJson
that checks for error(s)
in the params – and load it in config/app.php
?
You could hack it in by creating a module with this:
use yii\base\Event;
use yii\web\Response;
Event::on(Response::class, Response::EVENT_BEFORE_SEND, function(Event $e) {
/** @var Response $response */
$response = $e->sender;
if (
$response->format === Response::FORMAT_JSON &&
!empty($response->data['error']) &&
$response->getStatusCode() === 200 &&
\Craft::$app->getRequest()->getIsSiteRequest()
) {
$response->setStatusCode(400);
}
});
Most helpful comment
You could hack it in by creating a module with this: