Guzzle Get request with headers and query string - php

I'm trying to fetch data by GET request with using Guzzle client. I'm using both header with JWT token and query params like below:
function fetchUserByEmployeeId(string $employeeId): JsonResponse
{
$headers = $this->getHeaders();
$query = ['$filter' => "employeeId eq $employeeId", '$select' => 'displayName,givenName,postalCode,employeeId,id'];
try {
$result = $this->client->request('GET', self::FIND_USER_BY_EMPLOYEE_ID_URL, [
'headers' => $headers,
'query' => $query,
'debug' => true
]);
return JsonResponse::fromJsonString($result->getBody()->getContents());
} catch (RequestException $exception) {
throw $exception;
}
}
Unfortunaletely I've received an error like below:
If I delete $query it will work. Is there something wrong with my query params? I have no idea. Based on Guzzle documantation it seems to be ok: https://docs.guzzlephp.org/en/stable/request-options.html#query

Fortunately I have solved this issue. Problem was with passing param. $employeeId, should be in quotes. Like below:
function fetchUserByEmployeeId(string $employeeId): JsonResponse
{
$headers = $this->getHeaders();
$query = ["\$filter" => "employeeId eq '$employeeId'", "\$select" => "displayName,givenName,postalCode,employeeId,id"];
try {
$result = $this->client->request('GET', self::FIND_USER_BY_EMPLOYEE_ID_URL, [
RequestOptions::HEADERS => $headers,
RequestOptions::QUERY => $query,
'debug' => true
]);
return JsonResponse::fromJsonString($result->getBody()->getContents());
} catch (RequestException $exception) {
throw $exception;
}
}

Related

How to Retrieve Form Parameters sent on a Guzzle Exception?

How to Retrieve form_params used from a Guzzle BadResponseException (ClientException || ServerException) Object?
I couldn't find it in the documentation.
try {
$reponse = $this->client->post($uri, [
'form_params' => $params,
'headers' => $this->getHeaders()
]);
} catch (RequestException $e){
/// get form_params here without accessing $params
}
The form encoded parameters can be found on Request Body.
try {
$reponse = $this->client->post($uri, [
'form_params' => $params,
'headers' => $this->getHeaders()
]);
} catch (RequestException $e){
echo (string) $e->getRequest()->getBody();
}

How to send form fields with Guzzle 6?

I am developing my unit tests for an API created in Symfony4
Reading the Guzzle documentation I generated the following code:
File SecurityControllerTest.php
$client = new Client([
'base_uri' => 'http://localhost/sacrepad/sacrepad-api/public/index.php/',
'timeout' => 2.0,
]);
$data = array();
$data['email'] = 'admin#admin.com';
$data['password'] = '12345678';
$data2 = array();
$data2['json'] = $data;
$formData = json_encode($data);
$response = $client->request('POST', 'login', [
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'json' => $formData,
]
]);
$body = json_decode($response->getBody(), true);
File SecurityController.php
/**
* #Route("/login", name="login", methods={"POST"})
*/
public function login(Request $request,Helpers $helpers,ValidatorInterface $validator, JwtAuth $jwtauth) {
$data = array(
'status' => 'error',
'code' => 400,
'msg' => 'data not received'
);
$json = $request->request->get('json');
$params = json_decode($json);
}
When I run the tests with the phpunit command, I get the following error:
1) App\Tests\SecurityControllerTest::testAuth GuzzleHttp\Exception\ServerException: Server error: `POST http://localhost/sacrepad/sacrepad-api/public/index.php/login` resulted in a `500 Internal Server Error` response:
If I change the name of the request:
$json = $request->request->get('json2');
It works and it returns me the following:
array(3) {
["status"]=>
string(5) "error"
["code"]=>
int(400)
["msg"]=>
string(18) "data not received"
}
Any ideas on how to make it work and send the parameters?
i build a class for working with guzzle
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class Api
{
protected $client;
protected $url;
public function __construct()
{
$this->client = new Client([
'verify'=>false
]);
$this->url = 'http://localhost/sacrepad/sacrepad-api/public/';
}
public function get($endpoint, $params = [], $headers = [])
{
$response = $this->sendRequest(
'GET',
$this->url . $endpoint,
$params,
$headers
);
return $response;
}
public function post($endpoint, $params = [], $headers = [])
{
$response = $this->sendRequest(
'POST',
$this->url . $endpoint,
$params,
$headers
);
return $response;
}
public function sendRequest($type, $url, $params = [], $headers = [])
{
if ($type == 'GET') {
$data = [
'query' => $params
];
} elseif ($type == 'FILE') {
$type = 'POST';
$data = [
'multipart' => $params // TODO implements later
];
} else {
$data = [
'json' => $params
];
}
if (!empty($headers)) {
$data['headers'] = $headers;
}
$data['headers']['X-REAL-IP'] = $_SERVER['REMOTE_ADDR'];
$data['headers']['User-Agent'] = $_SERVER['HTTP_USER_AGENT'];;
$data['headers']['X-Platform'] = 'web';
try {
$response = $this->client->request(
$type,
$url,
$data
);
if (in_array($response->getStatusCode(), ['200', '403', '404'])) {
return json_decode($response->getBody());
}
return false;
} catch (RequestException $re) {
if (in_array($re->getResponse()->getStatusCode(), ['403', '404', '422'])) {
return json_decode($re->getResponse()->getBody());
}
return json_decode($re->getResponse()->getBody());
} catch (Exception $e) {
return false;
}
}
}
when i want to send a post request it would be like this
$response = (new Api())->post('index.php/',[
'email'=> 'admin#admin.com',
'password' => '123456'
]);
now it will send a post request to index.php and send email and password data i hope it would be helpful

Can I call a method from the same method?

I'm in a situation where I need to call the same method if any exception is thrown to ensure I'm not duplicating any code. However, it's not working as I thought. Here's the relevant code:
public static function getFolderObject($folder_id)
{
$client = new Client('https://api.box.com/{version}/folders', [
'version' => '2.0',
'request.options' => [
'headers' => [
'Authorization' => 'Bearer ' . self::getAccessToken(),
]
]
]);
$request = $client->get($folder_id);
try {
$response = $request->send();
$result = $response->json();
$files = $result['item_collection']['entries'];
} catch (BadResponseException $e) {
$result = $e->getResponse()->getStatusCode();
if ($result === 401) {
self::regenerateAccessToken();
self::getFolderObject();
}
}
return count($files) ? $files : false;
}
As you can see I'm calling the method from the method method under the if condition self::getFolderObject(); to prevent duplicate code again in under the if statement from beginning of the method. However, if I duplicate the code it works as expected. Is there any solution to achieve what I want?
You have missed to return the value and assign the folder_id:
public static function getFolderObject($folder_id)
{
$client = new Client('https://api.box.com/{version}/folders', [
'version' => '2.0',
'request.options' => [
'headers' => [
'Authorization' => 'Bearer ' . self::getAccessToken(),
]
]
]);
$request = $client->get($folder_id);
try {
$response = $request->send();
$result = $response->json();
$files = $result['item_collection']['entries'];
} catch (BadResponseException $e) {
$result = $e->getResponse()->getStatusCode();
if ($result === 401) {
self::regenerateAccessToken();
return self::getFolderObject($folder_id);
}
}
return count($files) ? $files : false;
}

how to post Guzzle 6 Async data

i trying to post data as Async with using Guzzle 6(latest ver)
$client = new Client();
$request = $client->postAsync($url, [
'json' => [
'company_name' => 'update Name'
],
]);
but i am not getting any request form Guzzle like post request on terminal
Because it's a promise, you need to put then
and the promise will not called unless you put $promise->wait()
This is a simple post request using postAsync based on your question:
$client = new Client();
$promise = $client->postAsync($url, [
'json' => [
'company_name' => 'update Name'
],
])->then(
function (ResponseInterface $res){
$response = json_decode($res->getBody()->getContents());
return $response;
},
function (RequestException $e) {
$response = [];
$response->data = $e->getMessage();
return $response;
}
);
$response = $promise->wait();
echo json_encode($response);
Have you tried to send the request?
http://guzzle.readthedocs.org/en/latest/index.html?highlight=async
$client = new Client();
$request = new Request('POST', $url, [
"json" => [
'company_name' => 'update Name']
]);
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
Guzzle 6 has very little practical examples/documentation for developers to refer. I am sharing an example on how to use postAsync and Pool object. This allows concurrent async requests using guzzle 6. ( I was not able to find a direct example and spent 2 days to get working code )
function postInBulk($inputs)
{
$client = new Client([
'base_uri' => 'https://a.b.com'
]);
$headers = [
'Authorization' => 'Bearer token_from_directus_user'
];
$requests = function ($a) use ($client, $headers) {
for ($i = 0; $i < count($a); $i++) {
yield function() use ($client, $headers) {
return $client->postAsync('https://a.com/project/items/collection', [
'headers' => $headers,
'json' => [
"snippet" => "snippet",
"rank" => "1",
"status" => "published"
]
]);
};
}
};
$pool = new Pool($client, $requests($inputs),[
'concurrency' => 5,
'fulfilled' => function (Response $response, $index) {
// this is delivered each successful response
},
'rejected' => function (RequestException $reason, $index) {
// this is delivered each failed request
},
]);
$pool->promise()->wait();
}
most likely you'll need to call wait();
$request->wait();

Symfony PHPUnit Test ( error 500 )

Im testing this function
/**
* #Route("/list", name="_clients")
* #Method("GET")
*/
public function ClientsAction()
{
$em = $this->getDoctrine()->getManager();
$data = $em->getRepository('InvoiceBundle:Clients')->findByUser($this->user());
if($data){
$Clients = array();
foreach($data as $v){
if($v->getCompanyId() != 0 ) {
$companyId = $v->getCompanyId();
} else {
$companyId = '';
}
if ($v->getClient() == 'person'){
$company = $v->getName().' '.$v->getLname();
} else {
$company = $v->getCompany();
}
$Clients[] = array(
'id' => $v->getId(),
'settings' => $company,
'companyId' => $companyId,
'client' => $v->getClient(),
'mobile' => $v->getMobile(),
'email' => $v->getEmail(),
'clientName' => $v->getClientName(),
'delivery' => $v->getDelivery(),
'ContactPerson' => $v->getContactPerson()
);
}
} else {
$Clients = array('data' => 'empty');
}
$response = new JsonResponse($Clients);
return $response;
}
The function it self runs correctly , but then i want to check if my 'Content-Type' is Json with this function
public function testClients()
{
$client = static::createClient();
$client->request('GET', '/clients/list');
$this->assertTrue(
$client->getResponse()->headers->contains(
'Content-Type',
'application/json'
)
);
}
with this i get a FALSE value.
Then i try to do a test for Status code
$this->assertSame(200, $client->getResponse()->getStatusCode());
With this i get error 500 instead of 200 OK
I understand that is why i get a FALSE value in my 'Content-Type' test but i cant get why.
Im doing all this according to the Symfony documentation.
May be i'm doing something wrong or is it just that you cant check the 'Content-Type'?
Any help would be appreciated!
JsonResponse does add the Content-Type header (application/json) so this should not be an issue.
I think the main issue is that you are missing $ on the client->request() line.
Edit :
Before the declaration of your class, did you add #Route("/clients") ?
Or, maybe the data returned by findByUser is not what you expected and calls to $v fail.

Categories