0

This controller (called via the __invoke function) calls another function to process some data, I would like to return a response on error from the second function processData, is it possible?

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args)
{
    $someData = ...;
    $processedData = $this->processData($someData, $response);
    return $response->withJson($processedData);
}

private function processData(ResponseInterface $response)
{
    ...
    $error = true; // simulate error
    if($error){
        return $response->withJson('error', 500);
    } else {
        return $processedData;
    }
}

Returning an error response from a subfunction call does not work since the response has to be returned from the main function.

How can I achieve this?

One solution is to throw an error from the subfunction but I would like to return proper slim responses.

Ploppy
  • 14,810
  • 6
  • 41
  • 58
  • 1
    Is `$processedData` (returned from `processData()`) also of type `ResponseInterface`? – Nima Oct 01 '19 at 11:31
  • `processData()` is supposed to returned modified data, not a `ResponseInterface`, though I would like to be able to throw a Slim error response in the `processData()` if necessary. Hope it is clear enough. – Ploppy Oct 01 '19 at 12:20

1 Answers1

1

As I understand processData() returns the response object in case of any errors occur, but returns another type of data otherwise. This means this method is returning two different types of data in different situations, so in your controller you need to handle its return value differently: if it is returning a response object, you can return it as is, but if it returns the processed data, you need to return a json response built using that data...this makes things a little confusing.

Your idea about throwing an error seems fine, and you should know you can (and you must) return a proper response in case of any error. That is why a Slim error handler should return a response object.

To refactor your code, I see these options:

  1. Throw an exception in processData() and define some custom exception classes and write a good error handler to produce the correct error response (recommended)
private function processData(ResponseInterface $response)
{
    ...
    $error = true; // simulate error
    if($error){
        throw new DataProcessingException('Details about why this happened');
    }
    return $processedData;
}
// in your controller

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args)
{
    $someData = ...;
    $processedData = $this->processData($someData, $response);
    return $response->withJson($processedData);
}

// in error handler

...
catch (\DataProcessingException $e) {
    return $response->withJson(['error' => 'A data processing exception has occurred', 'details' => $e->getMessage()], 500);
}
  1. Throw an exception in processData() on any error and handle it in controller:
private function processData(ResponseInterface $response)
{
    ...
    $error = true; // simulate error
    if($error){
        throw new \Exception('error message');
    }
    return $processedData;
}

// in your controller

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args)
{
    $someData = ...;
    try {
        $processedData = $this->processData($someData, $response);
        return $response->withJson($processedData);
    }
    catch (\Exception $e) {
        return $response->withJson('error', 500);
    }
}
  1. In processData(), return $processedData or some value (FALSE for example) to indicate an error, and in controller, generate a corresponding response (not recommended):
private function processData(ResponseInterface $response)
{
    ...
    $error = true; // simulate error
    if($error){
        return false;
    }
    return $processedData;
}
// in your controller

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args)
{
    $someData = ...;
    $processedData = $this->processData($someData, $response);
    if ($processedData === false) {
        return $response->withJson('error', 500);
    }
    return $response->withJson($processedData);

}
Nima
  • 3,309
  • 6
  • 27
  • 44
  • Could you please add some information about the error handler. I'm not sure how to set it up properly. – Ploppy Oct 01 '19 at 15:25
  • Which version of Slim are you using? – Nima Oct 02 '19 at 02:51
  • I am using slim 3, – Ploppy Oct 02 '19 at 05:05
  • Did you try to write your own error handler? Have a look at here https://www.slimframework.com/docs/v3/handlers/error.html to learn how, and please note, your custom error handler receives an `$exception` which you can check to handle different types of exceptions differently. – Nima Oct 02 '19 at 05:43