I would like to handle errors from Guzzle when the server returns 4xx and 5xx status codes. I make a request like this:
$client = $this->getGuzzleClient();
$request = $client->post($url, $headers, $value);
try {
$response = $request->send();
return $response->getBody();
} catch (\Exception $e) {
// How can I get the response body?
}
$e->getMessage returns code info but not the body of the HTTP response. How can I get the response body?
Guzzle 6.x
Per the docs, the exception types you may need to catch are:
GuzzleHttp\Exception\ClientException for 400-level errors
GuzzleHttp\Exception\ServerException for 500-level errors
GuzzleHttp\Exception\BadResponseException for both (it's their superclass)
Code to handle such errors thus now looks something like this:
$client = new GuzzleHttp\Client;
try {
$client->get('http://google.com/nosuchpage');
}
catch (GuzzleHttp\Exception\ClientException $e) {
$response = $e->getResponse();
$responseBodyAsString = $response->getBody()->getContents();
}
Guzzle 3.x
Per the docs, you can catch the appropriate exception type (ClientErrorResponseException for 4xx errors) and call its getResponse() method to get the response object, then call getBody() on that:
use Guzzle\Http\Exception\ClientErrorResponseException;
...
try {
$response = $request->send();
} catch (ClientErrorResponseException $exception) {
$responseBody = $exception->getResponse()->getBody(true);
}
Passing true to the getBody function indicates that you want to get the response body as a string. Otherwise you will get it as instance of class Guzzle\Http\EntityBody.
While the answers above are good they will not catch network errors. As Mark mentioned, BadResponseException is just a super class for ClientException and ServerException. But RequestException is also a super class of BadResponseException. RequestException will be thrown for not only 400 and 500 errors but network errors and infinite redirects too. So let's say you request the page below but your network is playing up and your catch is only expecting a BadResponseException. Well your application will throw an error.
It's better in this case to expect RequestException and check for a response.
try {
$client->get('http://123123123.com')
} catch (RequestException $e) {
// If there are network errors, we need to ensure the application doesn't crash.
// if $e->hasResponse is not null we can attempt to get the message
// Otherwise, we'll just pass a network unavailable message.
if ($e->hasResponse()) {
$exception = (string) $e->getResponse()->getBody();
$exception = json_decode($exception);
return new JsonResponse($exception, $e->getCode());
} else {
return new JsonResponse($e->getMessage(), 503);
}
}
As of 2020 here is what I elaborated from the answers above and Guzzle docs to handle the exception, get the response body, status code, message and the other sometimes valuable response items.
try {
/**
* We use Guzzle to make an HTTP request somewhere in the
* following theMethodMayThrowException().
*/
$result = theMethodMayThrowException();
} catch (\GuzzleHttp\Exception\RequestException $e) {
/**
* Here we actually catch the instance of GuzzleHttp\Psr7\Response
* (find it in ./vendor/guzzlehttp/psr7/src/Response.php) with all
* its own and its 'Message' trait's methods. See more explanations below.
*
* So you can have: HTTP status code, message, headers and body.
* Just check the exception object has the response before.
*/
if ($e->hasResponse()) {
$response = $e->getResponse();
var_dump($response->getStatusCode()); // HTTP status code;
var_dump($response->getReasonPhrase()); // Response message;
var_dump((string) $response->getBody()); // Body, normally it is JSON;
var_dump(json_decode((string) $response->getBody())); // Body as the decoded JSON;
var_dump($response->getHeaders()); // Headers array;
var_dump($response->hasHeader('Content-Type')); // Is the header presented?
var_dump($response->getHeader('Content-Type')[0]); // Concrete header value;
}
}
// process $result etc. ...
Voila. You get the response's information in conveniently separated items.
Side Notes:
With catch clause we catch the inheritance chain PHP root exception class
\Exception as Guzzle custom exceptions extend it.
This approach may be useful for use cases where Guzzle is used under the hood like in Laravel or AWS API PHP SDK so you cannot catch the genuine Guzzle exception.
In this case, the exception class may not be the one mentioned in the Guzzle docs (e.g. GuzzleHttp\Exception\RequestException as the root exception for Guzzle).
So you have to catch \Exception instead but bear in mind it is still the Guzzle exception class instance.
Though use with care. Those wrappers may make Guzzle $e->getResponse() object's genuine methods not available. In this case, you will have to look at the wrapper's actual exception source code and find out how to get status, message, etc. instead of using Guzzle $response's methods.
If you call Guzzle directly yourself you can catch GuzzleHttp\Exception\RequestException or any other one mentioned in their exceptions docs with respect to your use case conditions.
if put 'http_errors' => false in guzzle request options, then it would stop throw exception while get 4xx or 5xx error, like this: $client->get(url, ['http_errors' => false]). then you parse the response, not matter it's ok or error, it would be in the response
for more info
The question was:
I would like to handle errors from Guzzle when the server returns 4xx and 5xx status codes
While you can handle 4xx or 5xx status codes specifically, in practice it makes sense to catch all exceptions and handle the results accordingly.
The question is also, whether you just want to handle the errors or get the body? I think in most cases it would be sufficient to handle the errors and not get the message body or only get the body in the case of a non-error.
I would look at the documentation to check how your version of Guzzle handles it because this may change: https://docs.guzzlephp.org/en/stable/quickstart.html#exceptions
Also see this page in the official documentation on "Working with errors", which states:
Requests that receive a 4xx or 5xx response will throw a Guzzle\Http\Exception\BadResponseException. More specifically, 4xx errors throw a Guzzle\Http\Exception\ClientErrorResponseException, and 5xx errors throw a Guzzle\Http\Exception\ServerErrorResponseException. You can catch the specific exceptions or just catch the BadResponseException to deal with either type of error.
Guzzle 7 (from the docs):
. \RuntimeException
└── TransferException (implements GuzzleException)
└── RequestException
├── BadResponseException
│ ├── ServerException
│ └── ClientException
├── ConnectException
└── TooManyRedirectsException
So, your code might look like this:
use GuzzleHttp\Exception\TooManyRedirectsException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\ConnectException;
// ...
try {
$response = $client->request('GET', $url);
if ($response->getStatusCode() >= 300) {
// is HTTP status code (for non-exceptions)
$statusCode = $response->getStatusCode();
// handle error
} else {
// is valid URL
}
} catch (TooManyRedirectsException $e) {
// handle too many redirects
} catch (ClientException | ServerException $e) {
// ClientException is thrown for 400 level errors if the http_errors request option is set to true.
// ServerException is thrown for 500 level errors if the http_errors request option is set to true.
if ($e->hasResponse()) {
// is HTTP status code, e.g. 500
$statusCode = $e->getResponse()->getStatusCode();
}
} catch (ConnectException $e) {
// ConnectException is thrown in the event of a networking error.
// This may be an error reported by lowlevel functionality
// (e.g. cURL error)
$handlerContext = $e->getHandlerContext();
if ($handlerContext['errno'] ?? 0) {
// this is the lowlevel error code, not the HTTP status code!!!
// for example 6 for "Couldn't resolve host" (for libcurl)
$errno = (int)($handlerContext['errno']);
}
// get a description of the error
$errorMessage = $handlerContext['error'] ?? $e->getMessage();
} catch (\Exception $e) {
// fallback, in case of other exception
}
If you really need the body, you can retrieve it as usual:
https://docs.guzzlephp.org/en/stable/quickstart.html#using-responses
$body = $response->getBody();
Under the hood, by default cURL is used or PHP stream wrapper, see Guzzle docs, so the error codes and messages may reflect that:
Guzzle no longer requires cURL in order to send HTTP requests. Guzzle will use the PHP stream wrapper to send HTTP requests if cURL is not installed. Alternatively, you can provide your own HTTP handler used to send requests. Keep in mind that cURL is still required for sending concurrent requests.
Guzzle exceptions
libcurl error codes
HTTP status codes
The exception should be an instance of BadResponseException which has a getResponse method. You can then cast the response body to a string. Reference: https://github.com/guzzle/guzzle/issues/1105
use GuzzleHttp\Exception\BadResponseException;
$url = $this->baseUrl . "subnet?section=$section";
try {
$response = $this->client->get($url);
$subnets = json_decode($response->getBody(), true);
return $subnets['subnets'];
} catch (BadResponseException $ex) {
$response = $ex->getResponse();
$jsonBody = (string) $response->getBody();
// do something with json string...
}
None of the above responses are working for error that has no body but still has some describing text. For me, it was SSL certificate problem: unable to get local issuer certificate error. So I looked right into the code, because doc does't really say much, and did this (in Guzzle 7.1):
try {
// call here
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->hasResponse()) {
$response = $e->getResponse();
// message is in $response->getReasonPhrase()
} else {
$response = $e->getHandlerContext();
if (isset($response['error'])) {
// message is in $response['error']
} else {
// Unknown error occured!
}
}
}
For me, this worked with Guzzle inside a Laravel package:
try {
$response = $this->client->get($url);
}
catch(\Exception $e) {
$error = $e->getResponse();
dd($error);
}
You can get the whole error message (not truncated).
Please try the following code:
try {
...
} catch (GuzzleHttp\Exception\RequestException $e) {
$error = \GuzzleHttp\Psr7\str($e->getResponse());
print_r($error);
}
Related
I'm trying to modify my App\Exceptions\Handler to pass the request (and therefore current URL) through to all exceptions. For this reason I need the lowest-level exception class I can get hold of to type-hint to the ->renderable() method.
Laravel/Symfony's HttpException works but only for HTTP errors, leaving out all non-HTTP exceptions. PHP's Exception class works when using getCode() instead of getStatusCode(), but always returns a "0" for both HTTP errors and exceptions. Is there another low-level exception class that will work for my purposes, or otherwise any other way to accomplish what I'm trying to do here?
public function register()
{
$this->renderable(function (Exception $exception, $request) {
$url = $request->fullUrl();
$status = $exception->getCode();
Log::warning("Error $status when trying to visit $url. Received the following message: " . $exception->getMessage());
return response()->view("errors.$status", [
"exception" => $exception
],
$status
);
});
}
}
For what it's worth, I'm using the following web routes to trigger exceptions and HTTP errors for testing:
if (app()->environment('local')) {
Route::get("/exception", function (){
throw new JsonException; // chosen because it's one of the few Laravel exceptions
// that doesn't seem to automatically resolve to a HTTP error
});
}
if (app()->environment('local')) {
Route::get("/fail/{status}", function ($status){
abort($status);
});
}
As requested, this is what I have in my Handler. I use some custom logging, and I want to make sure I grab the right code when it's an HTTP error.
public function report(Throwable $e)
{
$code = match (get_class($e)) {
'Symfony\Component\HttpKernel\Exception\NotFoundHttpException' => 404,
\HttpException::class => $e->getStatusCode(),
default => 'No Code',
};
// more stuff here
}
You can use $e->getCode() for your default as well
You can throw your JsonException and abort like so with a given code and the handler should grab it from getCode like so
// in your controller
throw new \JsonException('Something went wrong', 500);
// or
abort(500, 'Something went wrong')
// in your handler
$status = $e->getCode(); // 500
$message = $e->getMessage(); // "Something went wrong"
That said it's better to keep them as semantically separate as possible in my opinion, and let the handler do the handling depending on what it receives.
I finally managed to figure this out in the end. It's probably not the cleanest solution, but it works perfectly for my needs.
It works by inspecting each instance of the Exception class and using PHP's instanceof() to check whether it's a HTTP exception or not. If it is, it gets logged with the request URL and returns a view with a status code. If it's a generic non-HTTP exception, it gets logged with the request URL and returns another view with no status code (or you can keep the default exception behaviour by removing the return block, which renders a blank screen in production).
public function register()
{
$this->renderable(function (Exception $exception, $request) {
$url = $request->fullUrl();
if ($exception instanceof HttpException) {
$status = $exception->getStatusCode();
Log::warning("Error $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
return response()->view("errors.error", [
"exception" => $exception,
"status" => $status
],
$status
);
} else {
$status = $exception->getCode();
Log::warning("Exception $status occurred when trying to visit $url. Received the following message: " . $exception->getMessage());
return response()->view("errors.exception", [
"exception" => $exception,
"status" => $status
]);
}
});
// Optionally suppress all Laravel's default logging for exceptions, so only your own logs go to the logfile
$this->reportable(function (Exception $e) {
})->stop();
}
I have this get organisations method in one project that talks to a central api project that handles all data like so:
public function searchOrganisations()
{
try {
return $this->client->request(.....);
} catch (Exception $ex) {
}
}
Within the api project a method is then hit and if a certain time frame criteria is hit I throw a custom exception like so:
public function searchOrganisations($searchRequest)
{
$experianCutOff = Carbon::createFromFormat('H:i:s', '06:00:00');
$now = Carbon::now()->setTime(02, 0, 0);
if (!$now->lt($experianCutOff)) {
return $data
} else {
throw new ExperianServiceException();
}
}
My custom exeption is as follows:
class ExperianServiceException extends Exception
{
public function render() {
return response()->json([
'message' => 'The Experian Service is currently unavailable, please try again at 0600 GMT'
], 503);
}
}
This works as expected and I catch the exception in the first method listed, I can access the status 503 and can see the message, however the message property of the exception always comes back in this format:
Server error: `POST http://docker.../search-organisations` resulted in a `503 Service Unavailable` response:
{"message":"The Experian Service is currently unavailable, please try again at 0600 GMT"}
It seems as though my supplied custom message has been concatenated with the standard Laravel Exception message (which I dont want). How can I make sure my message only contains what I supplied in my custom exception?
You could have your Exception implement Illuminate\Contracts\Support\Responsable and define the toResponse method to return that response. When you only have the render method the framework is still potentially going to do things to prepare the response. If it is Responsable it calls toResponse on it and returns that directly.
This causes a raw response from toResponse of your Exception to be returned without passing through any other parts of the Handler to be prepared in any way.
Maybe:
return Response::json(array(
'code' => 404,
'message' => $message
), 404);
I'm making a Remote::get request to an API which answers with http 500 when something goes wrong. The thing is that it also gives {errorCode: x} as a more detailed description of what went wrong in the response text. On some of the error codes I need to take different actions.
My problem is that Kohana throws an exception on http 500 responses and thus bakes in my easy parsable response text in a "wordy" error message in the exception object.
Is there some way to get the response text of the Remote::get on a http 500 response without having to parse a lengthy error description?
Impossible. Take a look at source code
if ($code AND $code < 200 OR $code > 299)
{
$error = $response;
}
...
if (isset($error))
{
throw new Kohana_Exception('Error fetching remote :url [ status :code ] :error',
array(':url' => $url, ':code' => $code, ':error' => $error));
}
Kohana_Exception doesn't help much
public function __construct($message, array $variables = NULL, $code = 0)
{
// Set the message
$message = __($message, $variables);
// Pass the message to the parent
parent::__construct($message, $code);
}
So it mixes all things into one message.
How about using different HTTP client? For example Guzzle - it is easier to retrieve the body on error.
function order_confirmationAction($order,$token) {
$client = new \GuzzleHttp\Client();
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $order)
);
$answer = json_decode($answer);
if ($answer->status=="ACK") {
return $this->render('AcmeDapiBundle:Orders:ack.html.twig', array(
'message' => $answer->message,
));
} else throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $answer->message);
}
If $client->post() response status code is an "Error 500" Symfony stops the script execution and throw new exception before the json decoding.
How can I force Symfony to ignore $client->post() bad response and execute till the last if statement?
$client = new \GuzzleHttp\Client();
try {
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $serialized_order)
);
}
catch (\GuzzleHttp\Exception\ServerException $e) {
if ($e->hasResponse()) {
$m = $e->getResponse()->json();
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $m['result']['message']);
}
}
I solved like this. In that way I can access to responses of remote server even if it returns an error 500 code.
Per Guzzle documentation:
Guzzle throws exceptions for errors that occur during a transfer.
Specifically, if the API responds with a 500 HTTP error, you shouldn't expect its content to be JSON, and you don't want to parse it, so you're better off re-throwing an exception from there already (or informing the user that something went wrong). I would suggest trying this out:
function order_confirmationAction($order, $token) {
$client = new \GuzzleHttp\Client();
try {
$answer = $client->post("http://www.fullcommerce.com/rest/public/Qtyresponse",
array('body' => $order)
);
}
catch (Exception $e) {
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $e->getMessage());
}
$answer = json_decode($answer);
if ($answer->status=="ACK") {
return $this->render('AcmeDapiBundle:Orders:ack.html.twig', array(
'message' => $answer->message,
));
} else {
throw new \Symfony\Component\HttpKernel\Exception\HttpException(500, $answer->message);
}
}
It is probably also a good idea to check for errors when JSON-decoding the response, because there could be surprises in the content you're getting (eg. wrong format, missing or unexpected fields or values, etc.).
I'm trying to catch exceptions from a set of tests I'm running on an API I'm developing and I'm using Guzzle to consume the API methods. I've got the tests wrapped in a try/catch block but it is still throwing unhandled exception errors. Adding an event listener as described in their docs doesn't seem to do anything. I need to be able to retrieve the responses that have HTTP codes of 500, 401, 400, in fact anything that isn't 200 as the system will set the most appropriate code based on the result of the call if it didn't work.
Current code example
foreach($tests as $test){
$client = new Client($api_url);
$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() == 401) {
$newResponse = new Response($event['response']->getStatusCode());
$event['response'] = $newResponse;
$event->stopPropagation();
}
});
try {
$client->setDefaultOption('query', $query_string);
$request = $client->get($api_version . $test['method'], array(), isset($test['query'])?$test['query']:array());
// Do something with Guzzle.
$response = $request->send();
displayTest($request, $response);
}
catch (Guzzle\Http\Exception\ClientErrorResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch (Guzzle\Http\Exception\ServerErrorResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch (Guzzle\Http\Exception\BadResponseException $e) {
$req = $e->getRequest();
$resp =$e->getResponse();
displayTest($req,$resp);
}
catch( Exception $e){
echo "AGH!";
}
unset($client);
$client=null;
}
Even with the specific catch block for the thrown exception type I am still getting back
Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]
and all execution on the page stops, as you'd expect. The addition of the BadResponseException catch allowed me to catch 404s correctly, but this doesn't seem to work for 500 or 401 responses. Can anyone suggest where I am going wrong please.
Depending on your project, disabling exceptions for guzzle might be necessary. Sometimes coding rules disallow exceptions for flow control. You can disable exceptions for Guzzle 3 like this:
$client = new \Guzzle\Http\Client($httpBase, array(
'request.options' => array(
'exceptions' => false,
)
));
This does not disable curl exceptions for something like timeouts, but now you can get every status code easily:
$request = $client->get($uri);
$response = $request->send();
$statuscode = $response->getStatusCode();
To check, if you got a valid code, you can use something like this:
if ($statuscode > 300) {
// Do some error handling
}
... or better handle all expected codes:
if (200 === $statuscode) {
// Do something
}
elseif (304 === $statuscode) {
// Nothing to do
}
elseif (404 === $statuscode) {
// Clean up DB or something like this
}
else {
throw new MyException("Invalid response from api...");
}
For Guzzle 5.3
$client = new \GuzzleHttp\Client(['defaults' => [ 'exceptions' => false ]] );
Thanks to #mika
For Guzzle 6
$client = new \GuzzleHttp\Client(['http_errors' => false]);
To catch Guzzle errors you can do something like this:
try {
$response = $client->get('/not_found.xml')->send();
} catch (Guzzle\Http\Exception\BadResponseException $e) {
echo 'Uh oh! ' . $e->getMessage();
}
... but, to be able to "log" or "resend" your request try something like this:
// Add custom error handling to any request created by this client
$client->getEventDispatcher()->addListener(
'request.error',
function(Event $event) {
//write log here ...
if ($event['response']->getStatusCode() == 401) {
// create new token and resend your request...
$newRequest = $event['request']->clone();
$newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken());
$newResponse = $newRequest->send();
// Set the response object of the request without firing more events
$event['response'] = $newResponse;
// You can also change the response and fire the normal chain of
// events by calling $event['request']->setResponse($newResponse);
// Stop other events from firing when you override 401 responses
$event->stopPropagation();
}
});
... or if you want to "stop event propagation" you can overridde event listener (with a higher priority than -255) and simply stop event propagation.
$client->getEventDispatcher()->addListener('request.error', function(Event $event) {
if ($event['response']->getStatusCode() != 200) {
// Stop other events from firing when you get stytus-code != 200
$event->stopPropagation();
}
});
thats a good idea to prevent guzzle errors like:
request.CRITICAL: Uncaught PHP Exception Guzzle\Http\Exception\ClientErrorResponseException: "Client error response
in your application.
In my case I was throwing Exception on a namespaced file, so php tried to catch My\Namespace\Exception therefore not catching any exceptions at all.
Worth checking if catch (Exception $e) is finding the right Exception class.
Just try catch (\Exception $e) (with that \ there) and see if it works.
If the Exception is being thrown in that try block then at worst case scenario Exception should be catching anything uncaught.
Consider that the first part of the test is throwing the Exception and wrap that in the try block as well.
You need to add a extra parameter with http_errors => false
$request = $client->get($url, ['http_errors' => false]);
I want to update the answer for exception handling in Psr-7 Guzzle, Guzzle7 and HTTPClient(expressive, minimal API around the Guzzle HTTP client provided by laravel).
Guzzle7 (same works for Guzzle 6 as well)
Using RequestException, RequestException catches any exception that can be thrown while transferring requests.
try{
$client = new \GuzzleHttp\Client(['headers' => ['Authorization' => 'Bearer ' . $token]]);
$guzzleResponse = $client->get('/foobar');
// or can use
// $guzzleResponse = $client->request('GET', '/foobar')
if ($guzzleResponse->getStatusCode() == 200) {
$response = json_decode($guzzleResponse->getBody(),true);
//perform your action with $response
}
}
catch(\GuzzleHttp\Exception\RequestException $e){
// you can catch here 400 response errors and 500 response errors
// You can either use logs here use Illuminate\Support\Facades\Log;
$error['error'] = $e->getMessage();
$error['request'] = $e->getRequest();
if($e->hasResponse()){
if ($e->getResponse()->getStatusCode() == '400'){
$error['response'] = $e->getResponse();
}
}
Log::error('Error occurred in get request.', ['error' => $error]);
}catch(Exception $e){
//other errors
}
Psr7 Guzzle
use GuzzleHttp\Psr7;
use GuzzleHttp\Exception\RequestException;
try {
$client->request('GET', '/foo');
} catch (RequestException $e) {
$error['error'] = $e->getMessage();
$error['request'] = Psr7\Message::toString($e->getRequest());
if ($e->hasResponse()) {
$error['response'] = Psr7\Message::toString($e->getResponse());
}
Log::error('Error occurred in get request.', ['error' => $error]);
}
For HTTPClient
use Illuminate\Support\Facades\Http;
try{
$response = Http::get('http://api.foo.com');
if($response->successful()){
$reply = $response->json();
}
if($response->failed()){
if($response->clientError()){
//catch all 400 exceptions
Log::debug('client Error occurred in get request.');
$response->throw();
}
if($response->serverError()){
//catch all 500 exceptions
Log::debug('server Error occurred in get request.');
$response->throw();
}
}
}catch(Exception $e){
//catch the exception here
}
Old question, but Guzzle adds the response within the exception object. So a simple try-catch on GuzzleHttp\Exception\ClientException and then using getResponse on that exception to see what 400-level error and continuing from there.
I was catching GuzzleHttp\Exception\BadResponseException as #dado is suggesting. But one day I got GuzzleHttp\Exception\ConnectException when DNS for domain wasn't available.
So my suggestion is - catch GuzzleHttp\Exception\ConnectException to be safe about DNS errors as well.
If you are using the latest version say 6^ and you have a JSON parameter, you can add 'http_errors' => false to the array together with the JSON as seen below
I was looking out for away to do this i.e with my JSON in there but couldn't find a straight answer.