Is there a clean, easy way to throw php exceptions through a json response jquery/ajax call.
If all the errors should be treated in the same way (showing a dialog for example). You can do it this way:
PHP End:
public function throwJsonException($msg) {
echo json_encode(array('error'=> true, 'msg' => $msg));
}
throwJsonException('login invalid!');
jQuery End:
$(document).ajaxSuccess(function(evt, request, settings){
var data=request.responseText;
if (data.length>0) {
var resp=$.parseJSON(data);
if (resp.error)
{
showDialog(resp.msg);
return;
}
}
});
As a complement to the previous answers, instead of repeating the same code for json encoding in all your exceptions, you could set an exception handler to be used only in the needed scripts. For instance:
function ajaxExceptionHandler($e) {
echo json_encode(array(
'error' => array(
'code' => $e->getCode(),
'msg' => $e->getMessage())
));
}
Then, in your ajax handler,
set_exception_handler('ajaxExceptionHandler');
You could do something like this in PHP (assuming this gets called via AJAX):
<?php
try {
if (some_bad_condition) {
throw new Exception('Test error', 123);
}
echo json_encode(array(
'result' => 'vanilla!',
));
} catch (Exception $e) {
echo json_encode(array(
'error' => array(
'msg' => $e->getMessage(),
'code' => $e->getCode(),
),
));
}
In JavaScript:
$.ajax({
// ...
success: function(data) {
if (data.error) {
// handle the error
throw data.error.msg;
}
alert(data.result);
}
});
You can also trigger the error:
handler of $.ajax() by returning a 400 (for example) header:
header('HTTP/1.0 400 Bad error');
Or use Status:
if you're on FastCGI. Note that the error:
handler doesn't receive the error details; to accomplish that you have to override how $.ajax()
works :)
Facebook do something in their PHP SDK where they throw an exception if a HTTP request failed for whatever reason. You could take this approach, and just return the error and exception details if an exception is thrown:
<?php
header('Content-Type: application/json');
try {
// something; result successful
echo json_encode(array(
'results' => $results
));
}
catch (Exception $e) {
echo json_encode(array(
'error' => array(
'code' => $e->getCode(),
'message' => $e->getMessage()
)
));
}
You can then just listen for the error
key in your AJAX calls in JavaScript:
<script>
$.getJSON('http://example.com/some_endpoint.php', function(response) {
if (response.error) {
// an error occurred
}
else {
$.each(response.results, function(i, result) {
// do something with each result
});
}
});
</script>
I use this approach to convert Exceptions to JSON:
<?php
namespace MyApp\Utility;
use Throwable;
trait JsonExceptionTrait
{
public function jsonException(Throwable $exception)
{
return json_encode([
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace()
]);
}
}
then, simply in my controllers:
<?php
namespace MyApp\Controller;
use MyApp\Utility\JsonExceptionTrait;
class UserController extends AbstractController
{
use JsonExceptionTrait;
/**
* @param int $userId
* @return JsonResponse
*/
public function getAction(int $userId): JsonResponse
{
try {
$user = $this->userService->getUser($userId);
return new Response($user);
} catch (EntityNotFoundException $exception) {
return new Response(
$this->jsonException($exception),
JsonResponse::HTTP_NOT_FOUND
);
}
}