3

I developed an API using Slim v3, when an exception is raised I have an ErrorHandler which return the following:

public function __invoke(Request $request, Response $response, \Exception $exception)
{
    $status = $exception->getCode() ? : 500;
    $error = [
        "status" => ERROR_MSG,
        "data" => [
            "stack_trace" => ($this->_container['settings']['displayErrorDetails']) ? $exception->getTraceAsString() : '',
        ],
        "message" => $exception->getMessage()
    ];

    $body = json_encode($error, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

    return $response
        ->withStatus($status)
        ->withHeader("Content-type", "application/json")
        ->write($body);
}

so essentially when an exception happen in the API such as:

throw new Exception('Invalid user credentials');

The API will return this response:

{
    "status": "error",
    "data": {
        "stack_trace": "some stack trace.."
    },
    "message": "Invalid user credentials"
}

now the problem's that when I launch the request using curl I only get:

string(59) "The requested URL returned error: 500 Internal Server Error"

from the following code:

curl_error($this->session);

where $this->session contains the request.

I also tried to debug the request using:

$this->response = curl_exec($this->session);
$this->info = curl_getinfo($this->session);
$errno = curl_errno($this->session);
$error = curl_error($this->session);

and I get:

bool(false)
array(26) {
  ["url"]=>
  string(48) "http://localhost/ci3-api/v1/installation/install"
  ["content_type"]=>
  NULL
  ["http_code"]=>
  int(500)
  ["header_size"]=>
  int(0)
  ["request_size"]=>
  int(148)
  ["filetime"]=>
  int(-1)
  ["ssl_verify_result"]=>
  int(0)
  ["redirect_count"]=>
  int(0)
  ["total_time"]=>
  float(0.25)
  ["namelookup_time"]=>
  float(0.016)
  ["connect_time"]=>
  float(0.219)
  ["pretransfer_time"]=>
  float(0.219)
  ["size_upload"]=>
  float(0)
  ["size_download"]=>
  float(0)
  ["speed_download"]=>
  float(0)
  ["speed_upload"]=>
  float(0)
  ["download_content_length"]=>
  float(-1)
  ["upload_content_length"]=>
  float(0)
  ["starttransfer_time"]=>
  float(0.25)
  ["redirect_time"]=>
  float(0)
  ["redirect_url"]=>
  string(0) ""
  ["primary_ip"]=>
  string(9) "127.0.0.1"
  ["certinfo"]=>
  array(0) {
  }
  ["primary_port"]=>
  int(80)
  ["local_ip"]=>
  string(9) "127.0.0.1"
  ["local_port"]=>
  int(65036)
}
int(22)
string(59) "The requested URL returned error: 500 Internal Server Error"

how can I read the API response message? Seems impossible to do so when the error 500 is raised from the API. I tried with other error codes such as 400 and I can read the response, but with error code 500 I have the response always false.

sfarzoso
  • 1,356
  • 2
  • 24
  • 65
  • It's not immediately obvious from the question, but is `CURLOPT_RETURNTRANSFER` true and `var_dump($this->response);` is `bool(false)`? Also, random suggestions: showing the stack trace and exception message may not be a good idea in case there are any unhandled exceptions that aren't thrown by your code. Additionally, `Invalid user credentials` should be a 401. You might want to make a special exception that will be recognized by the error handler, and any general exceptions should just return a generic error message, not the exception message. – drew010 Jul 29 '19 at 20:21
  • The option `CURLOPT_RETURNTRANSFER` is setted to true, and the response is always false when an exception happen. I show the stack trace just in the development process, so I can easily debug the request. The exception above, about the credentials, is just an example. So if I understood well, I should return an error code which is not 500 when an exception happen? – sfarzoso Jul 29 '19 at 21:00

2 Answers2

2

this is my setup; I think important for you is CURLOPT_RETURNTRANSFER and mainly CURLOPT_FAILONERROR

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'your api url');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FAILONERROR, false); // this is important for you I think

// other stuff you need to set

$output = curl_exec($ch);

$curlError = curl_error($ch);
$curlErrNo = curl_errno($ch);
$httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);

if($output === false) {
// if header CURLOPT_FAILONERROR is true, always throw here
throw new RuntimeException('curl fail');
}

curl_close($ch);
// here process your output
jDolba
  • 391
  • 1
  • 8
1

The key is to set CURLOPT_FAILONERROR to false. I had the same problem getting the response body from a third-party web service when its http response code was >= 400, and this fixed the problem.

curl_setopt($ch, CURLOPT_FAILONERROR, false);
Don't Panic
  • 13,965
  • 5
  • 32
  • 51