Gracefully handling Guzzle errors/exceptions - php

I'm using Guzzle to push some data to an API using the following:
$total_price = round($total_price * 100, 0);
$client = new \GuzzleHttp\Client();
$callback = $client->request('GET', 'https://exaple.com/subscription.js', [
'query' => [
'aid' => 'c-a-totm-uk',
'tid' => $order_id,
'subid' => $reference,
'rvn' => $total_price,
'cid' => $customer_id,
]
]);
$status = $callback->getStatusCode();
It's not handling the errors/exceptions at the moment.
I've been looking at this question https://stackoverflow.com/a/28416973/609630 but am I right in saying with failures it will cause a fatal error before it hits the following code?
if (404 === $statuscode) {
// Clean up DB or something like this
} else {
throw new MyException("Invalid response from api...");
}
How can I handle it properly without causing a fatal error? I'd like to record what any errors are (I can do the recording part, just need to output the error).

Related

Error: Failure when receiving data from the peer php GuzzleHttp

I'm trying to make post request and the post request is working but I'm not getting the response
$client = new \GuzzleHttp\Client(['headers' => ['Authorization' => 'Basic ' . 'token==']]);
$data = $client->post(
'url',
[
'form_params' => [
'address' => 'addreww',
'name' => 'Zia Sultan',
'phone_number' => '2136000000',
]
]
);
return $data;
What I'm getting in my insomnia
Error: Failure when receiving data from the peer
You're code is working, post method returns ResponseInterface, we need to fetch the content from it, we need to first fetch the StreamInterface by calling getBody() and chaining it will getContents() gives us the actual response. Keep debug mode On, to get find the exact error for Error: Failure when receiving data from the peer, and when this error occurs, share the entire trace with us
try {
$response = (new \GuzzleHttp\Client())->post(
'url',
[
'headers' => [
'Authorization' => 'Basic ' . 'token=='
],
'form_params' => [
'address' => 'addreww',
'name' => 'Zia Sultan',
'phone_number' => '2136000000',
],
// 'http_errors' => false, // Set to false to disable throwing exceptions on an HTTP protocol errors (i.e., 4xx and 5xx responses)
// 'debug' => true,
// 'connect_timeout' => 30 // number of seconds to wait while trying to connect to a server, Use 0 to wait indefinitely (the default behavior)
// 'read_timeout' => 10 // timeout to use when reading a streamed body, default value is default_socket_timeout in php.ini
// 'timeout' => 30 // the total timeout of the request in seconds. Use 0 to wait indefinitely (the default behavior).
]
);
return $response->getBody()->getContents();
} catch (Throwable $exception) {
print_r($exception);
}
I was returning the data only but I needed to return getBody() like this way
$data->getBody()
Its working now

Unable to receive response after sending request with Guzzle

I have a simple POST request using Guzzle from Laravel to send. I tested the request with Postman but it keeps sending request until timeout without returning any response data. I set up some URLs to return sample data and they work fine when testing separately. But when bring the URLs to the request to call from Guzzle, then this sending-request-till-forever happened. Hope you guys can help me shed some light on this problem.
Here is my request code:
$client = new Client();
$req = new Request('POST', 'http://13.114.233.87/api/ocr');
$reqData = $client->send($req, ['timeout' => 5]);
return $reqData;
Here are the handlers for each sample URL:
(1) http://13.114.233.87/api/ocr
Route::post('ocr', 'OcrController#postOcrData'); // routing
public function postOcrData()
{
return response()->json(collect([
'request_id' => rand(0, 9),
'result' => 0,
'error_code' => '',
'error_message' => ''
]));
}
(2) http://13.114.233.87/api/ocr/getResult/{id}
Route::get('ocr/getResult/{id}', 'OcrController#getOcrData'); // routing
public function getOcrData($id)
{
return response()->json(collect([
'request_id' => $id,
'result' => 0,
'error_code' => '',
'error_message' => '',
'fields' => []
]));
}

Omnipay - Empty Error Message

I have been working with this code for a while and still couldn't figure out what is the problem with it.
Maybe some of the code has a problem, but Omnipay didn't show anything as the error message.
Can anyone please help me find out my mistakes?
$gateway = Omnipay::create('Eway_RapidDirect');
write_log($gateway->getDefaultParameters());
$gateway->initialize([
'apiKey' => 'API KEY',
'password' => 'PASSWORD',
'testMode' => true
]);
$card = new CreditCard([
'number' => '4444333322221111',
'expiryMonth' => '6',
'expiryYear' => '2030',
'cvn' => '123'
]
);
$transaction = $gateway->purchase([
'amount' => '10.00',
'currency' => 'AUD',
'transactionId' => 'RAM0001',
'card' => $card,
]
);
$response = $transaction->send();
if ($response->isSuccessful()) {
write_log('success');
} else {
write_log('failed');
write_log($response->getMessage());
}
The code always print
[07-Aug-2018 09:07:01 UTC] failed
[07-Aug-2018 09:07:01 UTC]
Plugin github: Omnipay Eway
This issue was due to a bug in the OmniPay eWAY library where the authentication headers were not set. Making matters worse, authentication failures aren't handled gracefully, resulting in the blank error message.
Version 3.0.1 contains a fix for the missing authentication.

Php unit test 401

When I try to test my api with the following code:
$client = new Client();
$res = $client->request('POST', $this->url.'/api/v1/school/1', [
'form_params' => [
'currentUserId' => 1
]
]); //line 22
$obj = json_decode($res->getBody());
$result = $obj->{'result'}->{'message'};
$this->assertEquals('Error', $result);
It is not going further then line 22 (see comment). When I post to the same url in postman the result is (with status code 401):
{
"result": {
"message": "Error",
"school": "Error show school"
}
}
But why is it not going further in my unit test? when I make 200 as response it is going further!
I can't comment your question so I will need to ask in my answer. What kind of error do you receive in line 22 or why does the script break? Do you have enabled error-reporting and/or checked the log-files?
Try to dump $res if there is no error/exception thrown.
Found an answer! You have to add:
['http_errors' => false]
Method now:
$client = new Client();
$res = $client->request('POST', $this->url.'/api/v1/school/1',['http_errors' => false], [
'form_params' => [
'currentUserId' => 1
]
]);
Although Jamie's answer seems to work but there is a very small detail you should be careful of. If you use :
$client = new Client();
$res = $client->request('POST', $this->url.'/api/v1/school/1',['http_errors' => false], [
'form_params' => ['currentUserId' => 1]
]);
as in Jamie's answer, you will always get 200 status code, even if you provide wrong credentials and you was supposed to get 401, that's why this code will never block your process but that doesn't mean your motive to check against 401 status is fulfilled.
If you really wanna check if it returns 401 by phpunit, you should use it like this:
$client = new Client();
$res = $client->request('POST', $this->url.'/api/v1/school/1',[
'http_errors' => false,
'form_params' => ['currentUserId' => 1]
]);
$status = $response->getStatusCode();
$this->assertEquals(401,$status);
This will result OK as it will actually match returned code against 401.
I hope it's clear and helps

Omnipay 3Dsecure redirect

I am using Omnipay to allow users to pay using Cardsave.
I have the following:
\Omnipay::setTestMode(true);
$transactionId = date('YmdHis').$booking->space->id.$booking->user->id;
$response = $gateway->purchase([
'amount' => $booking->price,
'currency' => 'GBP',
'card' => $card,
'transactionId' => $transactionId,
'cancelUrl' => \base_url('cardsave/cancel/'.$booking->id),
'returnUrl' => \base_url('cardsave/confirm/'.$booking->id)
])->send();
if ($response->isSuccessful()) {
$transactionReference = $response->getTransactionReference();
//save the transaction reference in case of refund
return ['status' => 'success', 'message' => 'Reservation process complete'];
} elseif ($response->isRedirect()) {
\Log::info('3DSecure redirect');
$booking->addAdditional(['3dsecure_transaction_id' => $transactionId]);
return [
'status' => 'redirect',
'form_html' => $response->getRedirectResponse()->getContent()
];
}
throw new PaymentException ($response->getMessage());
and my confirm url goes to the following method:
$transactionId = $booking->getAdditional('3dsecure_transaction_id');
$response = $gateway->completePurchase([
'amount' => $amount,
'transactionId' => $transactionId,
'currency' => 'GBP',
])->send();
if ($response->isSuccessful()) {
$transactionReference = $response->getTransactionReference();
return $this->finalise($booking, $transactionReference);
} else {
$this->cancel($booking);
}
But looking through the code for league/omnipay-cardsave, I see the following:
$md = $this->httpRequest->request->get('MD');
$paRes = $this->httpRequest->request->get('PaRes');
if (empty($md) || empty($paRes)) {
throw new InvalidResponseException;
}
So my question is (and I realise it is probably dumb, but I can't seem to grok this, for some reason), where is that request coming from, if I just instantiated the gateway?
I think I am doing this wrong.
EDIT:
I have discovered that the return call from the 3DSecure thing comes with the MD and PaRes values as POST parameters. This allows me to set them on the gateway. How do I do that? Is it done automatically when I instantiate the gateway?
I was right, the question was dumb.
After reading the code, and trying it out, I found out that the AbstractGateway uses Symfony's request class to automatically pickup POST variables, amongst which are in this case, 'MD' and 'PaRes'.
In fact, it says so in the CompletePurchase class:
$md = $this->httpRequest->request->get('MD');
$paRes = $this->httpRequest->request->get('PaRes');
httpRequest is setup in AbstractGateway.
Basically, it just works.

Categories