Zend Framework 2 AbstractRestfulController - Exceptions as JSON - php

My goal is get a JSON like
{
"meta": {
"error_type": "error type",
"code": 400,
"error_message": "error msg"
}
}
In case something went wrong.
I tried to put the try catch block both in the rest controller's action and in the model but I get the whole exception stack (I mean with the layout + view)
What's the right way ?

Catch the exception in the controller action.
Return a JsonModel from the action containing exception information:
public function someAction()
{
try {
throw new Exception();
}
catch (Exception $e) {
return new JsonModel(array(
'meta' => array(
'code' => $e->getCode(),
'error_message' => $e->getMessage(),
//...
)
));
}
//...
}
Source: Returning JSON from a ZF2 controller action

[I tried to put the try catch block both in the action rest
controller]
I've just tried like
(I want my goal become true but
when only if something goes wrong :) )
public function create($data)
{
try{
$artist = $this->getRequest()->getPost('artist', null);
$title = $this->getRequest()->getPost('title', null);
$album = new Album();
$album->exchangeArray(array('artist'=>$artist,'title'=>$title));
$id = $this->getAlbumTable()->saveAlbum($album);
return $this->get($id);
}
catch (Exception $e) {
return new JsonModel(array(
'meta' =>array(
'code'=>500,
'error-num'=>$e->getCode(),
'error-msg'=>$e->getMessage(),
)
));
}
}
but as above it doesn't work
instead of json data i get the
whole default exception stack with layout.

Related

want to set exception for twilio

i am sending otp using twilio,laravel, message is working now, but i want to set exception for if message is not delivered etc i have tried like
public function send_otp()
{
try {
$account_sid = env('TWILIO_ACCOUNT_SID');
$auth_token = env('TWILIO_AUTH_TOKEN');
$number=Auth::user()->user_phone;
$client = new Client($account_sid, $auth_token);
$messages = $client->messages->create($number, array(
'From' => '+12533368077',
'Body' => Auth::user()->user_otp,
));
dd($messages);
//return $messages;
//throw new Exception();
} catch (Exception $e) {
return response()->json(['error' => true,'message'=>'Something went wrong'],200);
}
}
can you please help me with this
After setting env data did you clear cache?
php artisan config:cache
If you want to handle error - laravel has special logic for that. You need to just to catch that error and then make action, it is simple:
https://laravel.com/docs/5.6/errors
public function render($request, Exception $exception)
{
if ($exception instanceof CustomException) {
return response()->view('errors.custom', [], 500);
}
return parent::render($request, $exception);
}

json response via exception

I have created a worker class in Laravel.
The worker class communicate to with Lumen. If there is an error in Lumen it will response back in json to Laravel.
The worker class like this:-
class Worker {
public function put($ip, $user, $file)
{
try {
$response = $this->client->post('/put', ['form_params' => ['ip' => $ip,'username' => $user, 'file' => $file]]);
$responseBody = (string)$response->getBody();
// do something
} catch (ClientException | ServerException $e) {
return $this->handleRequestError($e);
}
}
protected function handleRequestError($e)
{
if ($e instanceof ClientException) {
if ($e->getCode() == 422) {
throw new WorkerValidationException((string)$e->getResponse()->getBody());
}
}
if ($e instanceof ServerException) {
$error = json_decode($e->getResponse()->getBody(), true);
if ($error['error_type'] == 'ftp') {
throw new FtpException((string)$e->getResponse()->getBody());
}
if ($error['error_type'] == 'somethingElse') {
throw new SomethingElseException((string)$e->getResponse()->getBody());
}
}
throw new \Exception((string) $e->getResponse()->getBody());
}
}
The handleRequestError() method read the value of $error['error_type'] and throw specific exception.
However, I want 2 or 3 error codes ($error['code']) to response back to the user with json format. What is good approach to do this?
Eg:
if (if ($error['error_type'] == 'ftp' && $error['code'] == 200) {
response(['success' => false, 'message' => 'could not connect']);
}
I don't want to put response logic in the worker class. Do I need to do it in Exception Handler?
You could bind an error type and error code identifier to the app container and have it create the correct exception class. For example:
app()->bind('type1-error1', ExceptionClass1::class);
app()->bind('type2-error2', ExceptionClass2::class);
app()->bind('type2-error3', ExceptionClass3::class);
These could be bound early in the application life cycle such as in AppServiceProvider boot(). Then the exception handler could resolve an instance of the correct exception based on the type-error combination using:
$e = app('type1-error1');
throw $e;
The container is a powerful tool at your disposal!

Using exceptions in a production environment: Can a try catch block 'return' booleans?

The app is built on the MVC pattern, so my controllers are separate from my models.
I am using two payment gateways, Stripe and PayPal and have moved the API code into a model called Payment_Model.php.
Both functions have huge try/catch blocks that throw all manner of errors when a payment fails which is a good thing for me, not so for a customer...
Here is a try catch block example
try {
Stripe::setApiKey($this->config->item('stripe_secret_key'));
$customer = Customer::create([
'email' => 'customer#example.com',
'source' => $this->input->post('stripe_token'),
]);
$charge = Charge::create([
'customer' => $customer->id,
'amount' => $option->price,
'currency' => 'eur',
"description" => "Demo Transaction", // #TODO
]);
} catch (Exception $e) {
} catch (Stripe_CardError $e) {
throw new Exception($e);
} catch (Stripe_InvalidRequestError $e) {
throw new Exception($e);
} catch (Stripe_AuthenticationError $e) {
throw new Exception($e);
} catch (Stripe_ApiConnectionError $e) {
throw new Exception($e);
} catch (Stripe_Error $e) {
throw new Exception($e);
} catch (Exception $e) {
throw new Exception($e);
}
I don't want to display these errors or exceptions in my production environment... instead I would like to replace throw new Exception($e) with false so that I can call the model function in my controller and if something goes wrong I can redirect the user to a decent error page...
So my question is this:
Can I return a boolean IF something bad is caught so that I can either redirect to a success page or an error page in my controller? Or am I missing the point of using exceptions?

How can I make Symfony2 ignore Guzzle Client bad response exception in my custom controller?

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.).

Zend Framework 2 : set reason phrase for error 404

I want my controller to return a 404 response when a model is not found and I want to specify a custom message, not the default "The requested controller was unable to dispatch the request."
I have tried specifying the reason in the ViewModel, setting the reasonPhrase from the response object... nothing seems to work. I am currently investigating how I can prevent the default behaviour, but if someone know before I do, that would just be great. (Perhaps there's a better way than the one I would find anyhow, too.)
Here is what I have, which does not work :
$userModel = $this->getUserModel();
if (empty($userModel)) {
$this->response->setStatusCode(404);
$this->response->setReasonPhrase('error-user-not-found');
return new ViewModel(array(
'content' => 'User not found',
));
}
Thanks.
Looks like you are confusing the reasponphrase and the reason variable passed on to the view. The reasonphrase is part of the http status code, like "Not Found" for 404. You probably don't want to change that.
Like #dphn is saying, I would recommend throwing your own Exception and attach a listener to the MvcEvent::EVENT_DISPATCH_ERROR which decides what to respond.
To get you started:
Controller
public function someAction()
{
throw new \Application\Exception\MyUserNotFoundException('This user does not exist');
}
Module
public function onBootstrap(MvcEvent $e)
{
$events = $e->getApplication()->getEventManager();
$events->attach(
MvcEvent::EVENT_DISPATCH_ERROR,
function(MvcEvent $e) {
$exception = $e->getParam('exception');
if (! $exception instanceof \Application\Exception\MyUserNotFoundException) {
return;
}
$model = new ViewModel(array(
'message' => $exception->getMessage(),
'reason' => 'error-user-not-found',
'exception' => $exception,
));
$model->setTemplate('error/application_error');
$e->getViewModel()->addChild($model);
$response = $e->getResponse();
$response->setStatusCode(404);
$e->stopPropagation();
return $model;
},
100
);
}
error/application_error.phtml
<h1><?php echo 'A ' . $this->exception->getStatusCode() . ' error occurred ?></h1>
<h2><?php echo $this->message ?></h2>
<?php
switch ($this->reason) {
case 'error-user-not-found':
$reasonMessage = 'User not found';
break;
}
echo $reasonMessage;
module.config.php
'view_manager' => array(
'error/application_error' => __DIR__ . '/../view/error/application_error.phtml',
),

Categories