5

I am building a simple REST API package using cURL and would like to catch an error and then return a view. I am able to throw an error if I dd($e) but if I try and return a view it just continues with the code after the catch function. Shouldn't PHP kill the process and just go to the login view?

try{    
    $response = Http::timeout(2)->asForm()->post('https://' . $this->ip_address, [
        'username' => $this->username,
        'password' => $this->password
    ]);

} catch(\Illuminate\Http\Client\ConnectionException $e) {
    return view('auth.login');
}

If I get a cURL timeout exception I just want to go back to the login page for now. If I put in a bogus IP address obviously it will timeout after 2 seconds, which is what I am testing.

Using Laravel Http client, how can I catch that error and display the auth login view?

miken32
  • 42,008
  • 16
  • 111
  • 154
Chad Priddle
  • 650
  • 2
  • 15
  • 32
  • I see a lot of outdated and obsolete coding techniques here. Use of `array()`, non-strict equality checks (`==`). But step one I would take would be to stop using those ancient curl functions. https://laravel.com/docs/8.x/http-client – miken32 Oct 22 '21 at 16:59
  • Good point, I will use Guzzle – Chad Priddle Oct 22 '21 at 17:05
  • Updated the code – Chad Priddle Oct 22 '21 at 17:56
  • It's likely you're not understanding how your code is being run, because if you have a return clause in your `catch` block, execution will absolutely stop after that. The only exception is if you have a `finally` block. – miken32 Oct 23 '21 at 20:50
  • Are you sure you're looking for the correct exception? Try just catching the `Throwable` interface instead of a specific exception class. – miken32 Oct 23 '21 at 20:50

3 Answers3

7

Unlike Guzzle, Laravel's HttpClient does not throw errors if the response is > 400.

You should simply use an if statement to check the response status code. See: https://laravel.com/docs/8.x/http-client#error-handling

You can call use the following checks:

// Determine if the status code is >= 200 and < 300...
$response->successful();

// Determine if the status code is >= 400...
$response->failed();

// Determine if the response has a 400 level status code...
$response->clientError();

// Determine if the response has a 500 level status code...
$response->serverError();

So in your case you can simply do something like this:

$response = Http::timeout(2)->asForm()->post('https://' . $this->ip_address, [
    'username' => $this->username,
    'password' => $this->password
]);

if ($response->failed()) {
    return view('your-view')->with([
        'message' => 'Failed.',
    ]);
}
Ozan Kurt
  • 3,731
  • 4
  • 18
  • 32
  • 2
    I had tried that. But I get error: Illuminate\Http\Client\ConnectionException cURL error 28: Connection timed out after 2000 milliseconds (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://123.123.123.123/ – Chad Priddle Oct 23 '21 at 16:38
  • Oh right, I missed that you use timeout(2). It will force the query to throw an exception if it times out. So its theoretically not a query problem. You should use try catch there. – Ozan Kurt Oct 23 '21 at 17:26
  • From the @ChadPriddle doc link, you can also try to use `$response->throw();` that will throw an exception on client or server error. – Mtxz Oct 25 '21 at 17:17
  • Thanks for the help. One of the biggest issues is that the API that I am calling would post back a 200 status even though it had a bad username and password in the post. So I had to do an if statement. Ultimately that is why try catch wasn't catching the error. – Chad Priddle Oct 27 '21 at 15:28
0

Could you try this please?

try {
    $response = Http::timeout(2)->asForm()->post('https://' . $this->ip_address, [
        'username' => $this->username,
        'password' => $this->password
    ]);
} catch(\Illuminate\Http\Client\ConnectionException $e) {
    return view('auth.login')->with('errorMessage', $e->getMessage());
}

And you can show the error on the frontend, like below;

@if(!empty($errorMessage))
  <div class="alert alert-danger"> {{ $errorMessage }}</div>
@endif
kdrmlhcn
  • 96
  • 4
  • 1
    “Try this” doesn’t constitute a good answer. What was wrong with the original code? What changes did you make? Why will those changes resolve the problem? – miken32 Oct 23 '21 at 11:44
  • This doesn't catch the error, it just keeps running the code passed the function on to the next function and fails on the next cURL call – Chad Priddle Oct 23 '21 at 16:46
0

It is better if you change your approach in using Laravel's HTTP client,

Move time-intensive tasks - like Http requests - to a job, and run that job in a background queue.

Then, for example, if you wanna use that Http request for authentication, handle your auth logic on that job, don't forget to log and handle exceptions.

afterward, protect your private routes using middlewares and make redirect unauthenticated users to your login page in that middleware.

I hope I could be clear