1
votes

In my routes.php, I have this:

$apiSettings = [
    'version' => 'v1',
    'prefix' => 'api',
    'protected' => true
];   
Route::api($apiSettings, function() {
    Route::get('venue', 'ApiDataController@venue');
});

The protected venue API route accesses a controller method. The controller method performs the Eloquent Query on a Venues model, and returns the response. This works perfectly. The issue is in if I want to return an error - I am unsure how to. Here is the Venue Method:

public function venue(){

    try {
        //Some code that returns an exception
    } catch(someexception $e) {
        //How do I return the exception such that Dingo will parse it into a proper JSON response?
    }
    $response = Venue::with('address')->get();
    return $response;

}

My attempted solution (in the try block):

try {
    //some code that returns an exception
} catch(someexception $e) {
    $response = array(
        'message' => 'some random exception message'
    );
    return Response::json($response, 403);
}

I got the following error when I attempted to do that: Argument 1 passed to Dingo\Api\Http\Response::makeFromExisting() must be an instance of Illuminate\Http\Response, instance of Illuminate\Http\JsonResponse given, called in /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php on line 165 and defined

Second Attempted Solution: From Dingo's Returning Errors, docs, I tested what would happen if I returned one of the exceptions:

public function venue(){
    throw new Symfony\Component\HttpKernel\Exception\ConflictHttpException('err);
}

However, instead of returning the error as a JSON response, a laravel error page comes up, with the following error displayed:

[internal function]: ApiDataController->venue()
#1 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(231):
call_user_func_array(Array, Array)
#2 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(93):
Illuminate\Routing\Controller->callAction('venue', Array)
#3 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(62):
Illuminate\Routing\ControllerDispatcher->call(Object(ApiDataController),
Object(Illuminate\Routing\Route), 'venue')
#4 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(930):
Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route),
Object(Dingo\Api\Http\InternalRequest), 'ApiDataControll...', 'venue')
#5 [internal function]: Illuminate\Routing\Router->Illuminate\Routing\{closure}()
#6 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(105):
call_user_func_array(Object(Closure), Array)
#7 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(996):
Illuminate\Routing\Route->run(Object(Dingo\Api\Http\InternalRequest))
#8 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(964):
Illuminate\Routing\Router->dispatchToRoute(Object(Dingo\Api\Http\InternalRequest))
#9 /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php(147):
Illuminate\Routing\Router->dispatch(Object(Dingo\Api\Http\InternalRequest))
#10 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(337): Dingo\Api\Routing\Router->dispatch(Object(Dingo\Api\Http\InternalRequest))
#11 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(278): Dingo\Api\Dispatcher->dispatch(Object(Dingo\Api\Http\InternalRequest))
#12 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(213): Dingo\Api\Dispatcher->queueRequest('get', 'venue', Array)
#13 /vagrant/www/planat-app/app/routes.php(51): Dingo\Api\Dispatcher->get('venue')
#14 [internal function]: {closure}()
#15 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(105):
call_user_func_array(Object(Closure), Array)
#16 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(996):
Illuminate\Routing\Route->run(Object(Illuminate\Http\Request))
#17 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(964):
Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#18 /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php(147):
Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#19 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(738):
Dingo\Api\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#20 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(708):
Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request))
#21 /vagrant/www/planat-app/vendor/dingo/api/src/Http/Middleware/RateLimit.php(97):
Illuminate\Foundation\Application->handle(Object(Illuminate\Http\Request),
1, true)
#22 /vagrant/www/planat-app/vendor/dingo/api/src/Http/Middleware/Authentication.php(102):
Dingo\Api\Http\Middleware\RateLimit->handle(Object(Illuminate\Http\Request),
1, true)
#23 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Session/Middleware.php(72):
Dingo\Api\Http\Middleware\Authentication->handle(Object(Illuminate\Http\Request),
1, true)
#24 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Cookie/Queue.php(47):
Illuminate\Session\Middleware->handle(Object(Illuminate\Http\Request),
1, true)
#25 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Cookie/Guard.php(51):
Illuminate\Cookie\Queue->handle(Object(Illuminate\Http\Request), 1,
true)
#26 /vagrant/www/planat-app/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23):
Illuminate\Cookie\Guard->handle(Object(Illuminate\Http\Request), 1,
true)
#27 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(606):
Stack\StackedHttpKernel->handle(Object(Illuminate\Http\Request))
#28 /vagrant/www/planat-app/public/index.php(49): Illuminate\Foundation\Application->run()
3
In the laravel error page, does it show the same "Argument 1 passed to Dingo\Api\Http\Response::makeFromExisting() must be an instance of Illuminate\Http\Response" or what does it show? I think it should show a different error now A more copy-pastable error message should be the last chunk in your app/storage/logs/laravel.log too. - Unnawut
I've updated the question with the stack trace from laravel.log - Muserk
I think it has to do with syntax error. Can you check that your controller action has correct braces and everything? Or post your controller action code here. - Unnawut
Would be nice too if you could get the error log two lines above [internal function]: - Unnawut
@Unnawut why you need to try catch and then response exception message. Dingo Will handle exception and will response exception message automatically. See the following example. { "message": "Undefined variable: x", "status_code": 500 } Api endpoint have a undefined variable "x" and dingo handle it appropriately - Tuhin Bepari

3 Answers

3
votes

As you are building api, you can catch similar types of exception globally. For example, if a user tried to get a customer with an ID which doesn't exists, then you could do this.

Customer::findOrFail($id);

then you could catch all of this type exception in app/start/global.php like this.

App::error(function(ModelNotFoundException $modelNotFoundException){
    $errorResponse = [
        'errors'    => 'Not found any resource',
        'message'   => $modelNotFoundException->getMessage()
    ];

    return Response::json($errorResponse, 404);     //404 = Not found
});
2
votes

Reading from Dingo's Returning Errors docs, it says:

Instead of manually creating and returning an error response you can simply throw an exception and the package will handle the exception and return an appropriate response.

The following is a list of all the supported exceptions that you should throw when you encounter an error.

Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException Symfony\Component\HttpKernel\Exception\BadRequestHttpException Symfony\Component\HttpKernel\Exception\ConflictHttpException Symfony\Component\HttpKernel\Exception\GoneHttpException Symfony\Component\HttpKernel\Exception\HttpException Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException Symfony\Component\HttpKernel\Exception\NotFoundHttpException Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException

It also supports some generic resource exceptions that you can pass validation errors onto as well:

Dingo\Api\Exception\DeleteResourceFailedException Dingo\Api\Exception\ResourceException Dingo\Api\Exception\StoreResourceFailedException Dingo\Api\Exception\UpdateResourceFailedException

So in short, you need to throw one of the exceptions above that Dingo supports back to Dingo. For example:

try {
    //Some code that returns an exception
} catch(SomeException $e) {
    throw new Symfony\Component\HttpKernel\Exception\HttpException($e->getMessage);
}

Or in fact, if the exception thrown is one of the type above, or one that extends them, you can just remove your try/catch clause completely. The exception should be automatically thrown back to Dingo to handle it.

0
votes

Please check this:

try {
    //some code that returns an exception
} catch(\Exception $e) {
    $response = array(
        'message' => 'some random exception message'
    );
    return response()->json($response, 403);
}

Please check and let me know.