Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
REST error handling
  • I am trying to streamline the response format for both successful calls and exceptions.  In my module there are some initialization methods in the router that are made before the controller is called via Request::forge()->execute().  It is possible due to a misconfiguration or ? that an error may occur before the controller is called.  In that case, I would want the exception to be processed through response() on a layer I've created on Controller_Rest, which prepares the output data structure before rendering.  It would make sense then that it would get the correct response format from Controller_Rest::response().

    I considered attempting an HMVC to a controller to dump exceptions to a method that can then flow the output through the response() method.  But there's an immediate problem with this:  Controller_Rest is going to force a method call based on the input method (action_ or get/post/etc - what it's designed to do).  Yet I need to somehow reach response() in order to get the same workflow without creating a publicly accessible method. 

    Further, the layer created above Controller_Rest is abstract and is not within the controller directory.  So instantiating and working from that layer is out.

    Simply, I'm trying to internally access the formatted output generated by response() from outside of the controller so the output format for both error and success is delivered the same, based on Controller_Rest's configuration.

    Any suggestions?  Am I making this way more complicated than it really is?  (which sounds like a great excuse for a vacation :)
  • I figured I would add something I'm currently experimenting with in the router.  But it just seems hack-like and still testing it out as I post and mainly here to give a little more visual of what I'm trying to do.  But if someone has a better suggestion, please share.

    $request = \Request::forge($requestUri, false);
    try {
          if (\Cms\Api::validate()) {
            return $request->execute($params);
          }
        } catch (\Exception $e) {
          ... //unrelated code for logging and stuff
            $restController = new \Cms\Controller_Api($request);
            $output = $restController->errorOutput($e); //Basically taking the exception, formatting the output structure and then pass on to response() for output format.
            echo $output;
            exit(1);
          }
        }
  • I think you're making it overly complex.

    Create a base REST controller that extends Controller_Rest. Give it an after() method that processes the returned result of your API method. Design a way to allow method to signal an error, and have the after() method detect and handle that too.

    Then have all your API controllers extend this base controller.

    But...

    In the REST world, it is custom to always return a JSON data structure, and use the HTTP status code to signal the result back to the caller.

    For example, return a 406 instead of a 200 when the input does not validate, and store the validation error messages in the returned JSON so the client can handle the errors.
  • That would work for any exception that may happen within the controller itself.  The challenge I'm running into is delivering any error that may precede the actual Request->execute() call in the router level but delivering such an error in the same output format defined in any response within the restful controller.

    Ah, perhaps my problem is misuse of the routes file.  Perhaps I should be running any "pre-controller" validation code in the before() on the Controller_Rest extension I created?  Makes sense.  Let me give that a try.

    Thanks, Harro!
  • I do have one more question.  If I were to try to catch any errors that would happen within the execution of the controller's method and attempt to deliver that in a format defined in the REST controller, where would that reside?  Is there an example where I can see that in action?

    I know before() and after() happen respectively around the method call.  But what about catching exceptions that may happen within the method itself without defining a try/catch within every method declaration?  Within router()?
  • HarroHarro
    Accepted Answer
    You can do any validation in the before() method of the controller if needed.

    In general, you should catch errors where they are likely to occur, or as close to it as possible, so you can handle them. The higher up the stack you do it, the less granular it will be.

    If you want some sort of last-resort, to pevent exceptions "leaking through", you can add a router()  method to your REST base controller. Have it call the requested method in a try/catch block and handle the exception there. Then no REST method can throw unhandled exceptions anymore, and it is still transparent for your caller and your REST controllers.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion