My data_array like this :
Array (
[0] => 1
[1] => 2
[2] => 3 )
My code like this :
public function test(Request $request)
{
$client = new GuzzleHttpClient();
...
$concat_data = implode(',', $data_array);
$result = $client->request('POST', $url, [
'headers'=>[
'content-type'=>'application/json',
'Authorization'=> 'Bearer '.auth()->user()->api_token
],
'json'=>['ids'=>[$concat_data]]
]);
$content = json_decode($result->getBody()->getContents());
}
If the code is executed, it does not work perfectly. It just updates the data with id = 1
But, if I try with static data like this :
public function test(Request $request)
{
$client = new GuzzleHttpClient();
...
$concat_data = implode(',', $data_array);
$result = $client->request('POST', $url, [
'headers'=>[
'content-type'=>'application/json',
'Authorization'=> 'Bearer '.auth()->user()->api_token
],
'json'=>['ids'=>[1,2,3]]
]);
$content = json_decode($result->getBody()->getContents());
}
It works. It success updates the data with id = 1, id = 2, and id = 3
It seems my way of storing implode results in an array is still wrong
How can I solve this problem?
Note
If the code executed, it will update value of ids
implode converts an array to a string, whereas from your working static version, it looks like the API accepts a raw array. You're sending it the string "1,2,3", which it doesn't understand.
You should be able to just use
'json' => ['ids' => $data_array]
and skip the implode call entirely.
Related
Please what wrong in my code, I want to send send a raw data to API server.
Sample raw data input in postman :
{
"LNTY_ID": 21,
"LNG_DOC_NO": "LPY/DPS/I/22/017092",
"REG_KODE": "PRE",
"LNG_DATE": "2022-07-01"
}
and below is my code in ci4 :
public function uploadData()
{
$client = \Config\Services::curlrequest();
$headers = [];
$data = [
"LNTY_ID" => 21,
"LNG_DOC_NO" => "LPY/I/22/017092",
"REG_KODE" => "PRE",
"LNG_DATE" => "2022-07-01"
];
$url = "http://192.168.0.1/data_entry/";
$response = $client->request('POST', $url, ['form_body' => $data, 'headers' => $headers, 'http_errors' => false]);
echo $response->getBody();
}
When I run that code I get error message Bad Request.
Thank you for your help.
Regards
Nyoman
The option name is form_params, not form_body. https://codeigniter.com/user_guide/libraries/curlrequest.html#form-params
I am trying to make an API request in the following format:
/api/v1/courses?enrollment_state=active&include[]=total_students&include[]=term
How can I do so using the HttpClient Component query string parameters?
$response = $client->request('GET', '/api/v1/courses', [
'query' => [
'enrollment_state' => 'active',
'include[]' => 'term',
'include[]' => 'total_students',
],
]);
As the above approach does not work due to duplicate array key?
I have also tried:
'include[]' => ['term', 'total_students']
To create the equivalent to:
https://www.example.com/?token=foo&abc[]=one&abc[]=two
Just do:
$client->request(
'GET',
'https://www.example.com/',
[
'query' => [
'token' => 'foo',
'abc' => ['one', 'two']
]
]
);
as #user1392897 says, #yivi snippet returns indexes in the url query string.
https://www.example.com/?foo[0]=bar&foo[1]=baz
That's because it use the http_build_query built in function and it's the function behaviour. You can read this thread php url query nested array with no index about it.
A workaround it to build the query string yourself from the array and append it to your url, the the 2nd parameter of the HttpClient->request() method.
function createQueryString(array $queryArray = []): ?string
{
$queryString = http_build_query($queryArray, '', '&', \PHP_QUERY_RFC3986);
$queryString = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '%5B%5D=', $queryString); //foo[]=x&foo[]=y
return '' !== $queryString ? $queryString : null;
}
$queryArray = [
'abc' => ['one', 'two']
];
$queryString = createQueryString($queryArray);
$url = 'https://www.example.com/';
if (is_string($queryString)) {
$url = sprintf('%s?%s', $url, $queryString);
}
$response = $client->request('GET', $url);
Using Guzzle, I'm consuming some external apis in JSON format,
usually I get the data with
$data = $request->getBody()->getContents();
But i can't get data from this different api.
It seems the data doesn't come in a 'Response Body'.
This api call works:
https://i.ibb.co/80Yk6dx/Screenshot-2.png
This doesn't work:
https://i.ibb.co/C239ghy/Screenshot-3.png
public function getRemoteCienciaVitaeDistinctions()
{
$client = new Client(['headers' => ['Accept' => 'application/json']]);
$request = $client->get(
'https://................/',
[
'auth' => ['...', '...'],
]
);
$data = $request->getBody()->getContents();
return $data;
}
the second call is working fine, but the response is empty,
as we can see in Screenshot-3, the Total = 0, so the response from this API is empty.
to handle that properly I suggest you this modification for your method :
public function getRemoteCienciaVitaeDistinctions()
{
$client = new Client(['headers' => ['Accept' => 'application/json']]);
$request = $client->get(
'https://................/',
[
'auth' => ['...', '...'],
]
);
//Notice that i have decoded the response from json objects to php array here.
$response = json_decode($request->getBody()->getContents());
if(isset($response->total) && $response->total == 0) return [];
return $response;
}
please check the documentation of the API that you are using
I am using Guzzle (v6.1.1) in PHP to make a POST request to a server. It works fine. I am adding some logging functions to log what was sent and received and I can't figure out how to get the data that Guzzle sent to the server. I can get the response just fine, but how do I get the sent data? (Which would be the JSON string.)
Here is the relevant portion of my code:
$client = new GuzzleHttp\Client(['base_uri' => $serviceUrlPayments ]);
try {
$response = $client->request('POST', 'Charge', [
'auth' => [$securenetId, $secureKey],
'json' => [ "amount" => $amount,
"paymentVaultToken" => array(
"customerId" => $customerId,
"paymentMethodId" => $token,
"publicKey" => $publicKey
),
"extendedInformation" => array(
"typeOfGoods" => $typeOfGoods,
"userDefinedFields" => $udfs,
"notes" => $Notes
),
'developerApplication'=> $developerApplication
]
]);
} catch (ServerErrorResponseException $e) {
echo (string) $e->getResponse()->getBody();
}
echo $response->getBody(); // THIS CORRECTLY SHOWS THE SERVER RESPONSE
echo $client->getBody(); // This doesn't work
echo $client->request->getBody(); // nor does this
Any help would be appreciated. I did try to look in Guzzle sourcecode for a function similar to getBody() that would work with the request, but I'm not a PHP expert so I didn't come up with anything helpful. I also searched Google a lot but found only people talking about getting the response back from the server, which I have no trouble with.
You can do this work by creating a Middleware.
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $request;
}));
$client = new Client([
'base_uri' => 'http://www.example.com/api/',
'handler' => $stack
]);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => [
"key" => "value",
"key2" => "value",
]
]);
This, however, is triggered before to receive the response. You may want to do something like this:
$stack->push(function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
return $handler($request, $options)->then(
function ($response) use ($request) {
// work here
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $response;
}
);
};
});
Using Guzzle 6.2.
I've been struggling with this for the last couple days too, while trying to build a method for auditing HTTP interactions with different APIs. The solution in my case was to simply rewind the request body.
The the request's body is actually implemented as a stream. So when the request is sent, Guzzle reads from the stream. Reading the complete stream moves the stream's internal pointer to the end. So when you call getContents() after the request has been made, the internal pointer is already at the end of the stream and returns nothing.
The solution? Rewind the pointer to the beginning and read the stream again.
<?php
// ...
$body = $request->getBody();
echo $body->getContents(); // -->nothing
// Rewind the stream
$body->rewind();
echo $body->getContents(); // -->The request body :)
My solution for Laravel from 5.7:
MessageFormatter works with variable substitutions, see this: https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
$stack = HandlerStack::create();
$stack->push(
Middleware::log(
Log::channel('single'),
new MessageFormatter('Req Body: {request}')
)
);
$client = new Client();
$response = $client->request(
'POST',
'https://url.com/go',
[
'headers' => [
"Content-Type" => "application/json",
'Authorization' => 'Bearer 123'
],
'json' => $menu,
'handler' => $stack
]
);
You can reproduce the data string created by the request by doing
$data = array(
"key" => "value",
"key2" => "value",
);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => $data,
]);
// ...
echo json_encode($data);
This will output your data as JSON string.
Documentation at http://php.net/manual/fr/function.json-encode.php
EDIT
Guzzle has a Request and a Response class (and many other).
Request has effectively a getQuery() method that returns an object containing your data as private, same as all other members.
Also you cannot access it.
This is why I think manually encode it is the easier solution.
If you want know what is done by Guzzle, it also have a Collection class that transform data and send it in request.
Guzzle client creates by default from this code
$client->get('https://example.com/{?a}', array('a' => array('c','d')));
this url
https://example.com/?a=c,d
What is the best practice to send array in query string in RESTful application? The question is, how can I determine on the server side whether c,d is a string or an array? Isn't it better to send arrays using square brackets, e.g. a[]=c&a[]=d? How can I set Guzzle to use square brackets? Or it is better to use JSON encoded variables? On the server side I'm using Tonic.
Working Solution:
$vars = array('state[]' => array('Assigned','New'), 'per_page' => $perPage, 'page' => $pageNumber);
$query = http_build_query($vars, null, '&');
$string = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', $query); // state[]=Assigned&state[]=New
$client = new Client([follow instruction to initialize your client ....]);
$response = $client->request('GET', $uri, ['query' => $string]);
Now you have same name parameters in your request.
Dung.
Source: http_build_query with same name parameters
It seems the answer is here.
I wanted to do something like ?status[]=first&status[]=second
You can do this in Guzzle like shown in the link above:
$client = new Client('http://test.com/api');
$request = $client->get('/resource');
$query = $request->getQuery();
$query->set('status', array('first', 'second'));
Guzzle has a helper function you can use called build_query(). This uses PHP's http_build_query().
Here's an example of how to use it:
$params = [
'a[]' => [
'c',
'd'
],
'page' => 1
];
$query = \GuzzleHttp\Psr7\build_query($params);
$response = $client->request('GET', 'https://example.com/', [
'query' => $query
]);
I'm not 100% sure this quite answers the question. But I found the question while looking for how to construct complex queries using Guzzle and none of the answers here were the solution I ended up using. I'm adding it here in case it's ever useful for any other devs.
Using Guzzle 6, you can do this type of request:
$endPoint = "https://example.com";
$queryParams = [
'a' => [
[
"b" => "c"
]
]
];
$options = [
'debug' => true, // so you can see what the request looks like
'query' => $queryParams
];
$client->request('GET', $endPoint, $options);
As a real world example, query params like this:
$queryParams = [
'filters' => [
[
"field" => "status",
"value" => "open",
"operator" => "equal"
],
[
"field" => "total",
"operator" => "greater_than",
"value" => 50
],
],
'limit' => 500,
'start' => 7
];
produce a url like this:
https://example.com?filters=[{"field":"status","operator":"equal","value":"open"},{"field":"total","operator":"less_than","value":50}]&limit=500&start=7
The point being that the query key of the $options array, seems very powerful. I'd recommend having a play with that before going down the route of writing complex regular expressions.
$query = array('x' => array(
'a',
'b',
'c'
));
$query_string = http_build_query($query, null, '&'); //build query string
$query_string = preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '[]=', $query_string); //x[]=a&x[]=b
$response = $guzzle->client->get($path, array('query' => $query_string)); //Make guzzle request
return json_decode($response->getBody()->getContents()); //Return JSON decoded array
This is how you can process x with array of values in guzzle, tested with version 6 or later