Transform a CURL POST request to GuzzleHttp Post - php

I've got this CURL that I'm executing on the command line and it successfully creates content in my CMS (Drupal 9).
curl \
--user username:9aqW72MUbFQR4EYh \
--header 'Accept: application/vnd.api+json' \
--header 'Content-type: application/vnd.api+json' \
--request POST http://www.domain.drupal/jsonapi/node/article \
--data-binary #payload.json
and the JSON file as:
{
"data": {
"type": "node--article",
"attributes": {
"title": "My custom title",
"body": {
"value": "Custom value",
"format": "plain_text"
}
}
}
}
Working like a charm and data is being created.
I've been trying to do this in GuzzleHttp but couldn't get it working.
Get is working:
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
$url = 'http://www.domain.drupal';
$content_client = new GuzzleHttp\Client([
'base_uri' => $url,
'timeout' => 20.0,
]);
$res = $content_client->request('GET', '/jsonapi/node/article/71adf560-044c-49e0-9461-af593bad0746');
For POST, I've got probably around 10 versions trial and error but nothing worked.
How can I POST my JSON/Content to Drupal or how can I correctly implement the CURL in Guzzle?

If you want a simple post request to send json body with your headers you can do it simply without using Psr7 Request. Guzzle utilizes PSR-7 as the HTTP message interface.
use GuzzleHttp\Client;
$url = 'http://www.domain.drupal';
$content_client = new Client([
'base_uri' => $url,
'timeout' => 20.0,
]);
$headers = [
'Content-type' => 'application/vnd.api+json',
'Accept' => 'application/vnd.api+json'
];
$payload['data'] = [
'type' => 'node--article',
'attributes' => [
"title" => "My custom title",
"body" => [
"value" => "Custom value",
"format" => "plain_text"
]
]
];
$guzzleResponse = $content_client->post('/jsonapi/node/article/71adf560-044c-49e0-9461-af593bad0746', [
'json' => json_encode($payload),
'headers' => $headers
]);
if ($guzzleResponse->getStatusCode() == 200) {
$response = json_decode($guzzleResponse->getBody());
}
You can write it in try catch block with using RequestException (see this Catching exceptions from Guzzle to know more about it.)

Related

Convert cURL to Guzzle Post sending json data

I have this cURL command that I need to convert to PHP using Guzzle 7. I've have been researching this for a few (well, more than a few) days and getting nowhere fast. The cURL command uses the Simpli.fi api to create an organization under the parent org.
curl -i -X POST -H "X-App-Key: xxxx-xx-xx-xx-xxxxxx" -H "X-User-Key: xxxx-xx-xx-xx-xxxxxx" \
-H "Content-Type: application/json" \
-d '{
"organization": {
"name": "My New Organization",
"parent_id": "5786",
"custom_id": "<Put your organization identifier here or omit this optional field>"
}
}' \
"https://app.simpli.fi/api/organizations"
I was able to convert it using this website but it doesn't use Guzzle: https://onlinedevtools.in/curl
Here's what it gave me:
include('vendor/rmccue/requests/library/Requests.php');
Requests::register_autoloader();
$headers = array(
'X-App-Key' => 'xxxx-xx-xx-xx-xxxxxx',
'X-User-Key' => 'xxxx-xx-xx-xx-xxxxxx',
'Content-Type' => 'application/json'
);
$data = '{\n "organization": {\n "name": "My New Organization",\n "parent_id": "5786",\n "custom_id": "<Put your organization identifier here or omit this optional field>"\n }\n }';
$response = Requests::post('https://app.simpli.fi/api/organizations', $headers, $data);
Here's what I've tried so far aside from the converted code above:
public static function createOrganization()
{
self::init();
$client = new Client(['debug' => true]);
$request = $client->request('POST',
self::$baseUrl.'/organizations', [
'multipart' => [
[
'name' => 'data',
'contents' => "{'organization':{'name':'Pete's Pet Pagoda','parent_id':'1052385'}}",
],
],
'headers' => [
'x-app-key' => self::$appKey,
'x-user-key' => self::$userKey,
'Content-Type' => 'application/json',
]
]);
dd($response = $request->getStatusCode());
}
I'm getting quite a few different errors however this is the latest:
curl_setopt_array(): cannot represent a stream of type Output as a STDIO FILE*
Can anyone tell me what I'm doing wrong? Is there something missing?
UPDATE: After further research into this issue and chatting with a developer on the Laracast Slack channel, I've come to learn that this is a bug with the ['debug' => true] option when running on a Windows system and is described on this GITHUB page: https://github.com/guzzle/guzzle/issues/1413
I'm running on a Windows 10 Pro system. I corrected it on my end by changing the debug option to use fopen() like this:
'debug' => fopen('php://stderr', 'w'),
I use PHPStorm. It suggested using the 'wb' to make it binary safe. After changing it, the post requests worked fine.
You need to use body, not multipart. You can also use json.
$request = $client->request('POST',
self::$baseUrl.'/organizations', [
'headers' => [
'x-app-key' => self::$appKey,
'x-user-key' => self::$userKey,
'Content-Type' => 'application/json',
],
'body' => [
'{"organization":
[
{
"name":"Pete`s Pet Pagoda",
"parent_id":"1052385"
}
]
}',
],
]);
method 2
You can pass array to the json request option and it will convert it to json when sending the guzzle request. No need to use header as application/json as it applies internally.
$client->request('POST',
self::$baseUrl.'/organizations', [
'headers' => [
'x-app-key' => self::$appKey,
'x-user-key' => self::$userKey,
'Content-Type' => 'application/json',
],
'json' => [
"organization" => [
[
"name" => "Pete`s Pet Pagoda"
"parent_id" => "1052385"
]
]
],
]);
I hope this will help you. For further debugging use Middleware::tap(find more help here middleware+json+request)
try{
$client = new Client();
$response = $client->request('POST', self::$baseUrl.'/organizations',
[
'headers' => [
'x-app-key' => self::$appKey,
'x-user-key' => self::$userKey,
'Content-Type' => 'application/json',
],
'json' => [
'organization' =>
[
"name" => "some_name_value",
"parent_id" => "id_here",
"custom_id" => "custom id here"
]
]
]);
$_response = json_decode($response->getBody()->getContents(), true);
}
catch(BadResponseException $e){
$response = $e->getResponse();
$errorArray = json_decode($response->getBody()->getContents(), true);
//echo "<pre>";
//print_r($errorArray);
//return some message from errorarray;
}

Convert cURL request to Guzzle Request using Laravel

I haven't tried using cUrl Request with API and converting it to Guzzle HTTP.
I need to convert this cUrl to a working guzzle http post request to try the API
curl -X POST
"https://urltosendblahblah" -H "Content-Type: application/json" -d
{
"outboundRewardRequest" : {
"app_id" : "B54z9Ug55zLh5rTGRT5g6hq64pGUq6ap",
"app_secret" : "f6554137d08f5607a696cd40741993758c411af3bb5f6c230270ec26e8d54126",
"rewards_token" : "I7SkxKYid_F_p-JSgTejow",
"address" : "9271051129",
"promo" : "LOAD 50"
}
}
Currently I had done this with my Guzzle Http but receiving 500 response
public function loadSample(){
$url = "";
$request = $this->client->post($url, [
'verify'=>false,
'outboundRewardRequest' => [
'app_id'=>'',
'app_secret'=> '',
'rewards_token'=>'==',
'address'=>'',
'promo'=>''
]
]);
$response = $request->getBody();
dd($response);
}
thank you!
$request = $this->client->post($url, [
'headers' => [
'verify' => false
],
'form_params' => ['outboundRewardRequest' => [
'app_id'=>'',
'app_secret'=> '',
'rewards_token'=>'==',
'address'=>'',
'promo'=>''
]],
'debug' => false,
]);
Try this approach when using guzzle. Your body parameters must be a part of the form_params array.
Also you can set your guzzle debugging to false so you don't have any issues there.
The expected key for the request body is body source. So try changing outboundRewardRequest to body.
Put your data in the json attribute or form_params depending on how it is received.
public function loadSample(){
$url = "";
$request = $this->client->post($url, [
'verify'=>false,
'json' => [
'outboundRewardRequest' => [
'app_id'=>'',
'app_secret'=> '',
'rewards_token'=>'==',
'address'=>'',
'promo'=>''
]
]
]);
$response = $request->getBody();
dd($response);
}

Missing parameter

I'm having trouble to pass the version parameter in a POST request using GuzzleHttp.
Client error: GET https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone resulted in a 400 Bad Request response: {"code":400,"sub_code":"C00005","error":"Missing a minor version parameter in the URL. To use the latest version, add th (truncated...)
This is the latest I've tried:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'form_params' => [
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]
]);
This was failing too:
$client = new \GuzzleHttp\Client([
'base_uri' => 'https://gateway.watsonplatform.net/'
]);
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'version' => '2017-09-21',
'tone_input' => $text,
'sentences' => true
]);
Failing as well if using GET instead of POST.
If I change the URI and add the version, then it works fine (well, it fails as it doesn't have the text to analyse in the request):
Change: tone-analyzer/api/v3/tone
To: tone-analyzer/api/v3/tone?version=2017-09-21
So, I guess the question is HOW DO YOU PASS URL PARAMETERS in a request using GuzzleHttp?
Note: my CURL command works fine (http 200):
curl -X POST -u "{username}":"{password}" --header 'Content-Type: text/plain' --header 'Accept: application/json' --header 'Content-Language: en' --header 'Accept-Language: en' -d 'I hate these new features On #ThisPhone after the update.\r\n \
I hate #ThisPhoneCompany products, you%27d have to torture me to get me to use #ThisPhone.\r\n \
The emojis in #ThisPhone are stupid.\r\n \
#ThisPhone is a useless, stupid waste of money.\r\n \
#ThisPhone is the worst phone I%27ve ever had - ever 😠.\r\n \
#ThisPhone another ripoff, lost all respect SHAME.\r\n \
I%27m worried my #ThisPhone is going to overheat like my brother%27s did.\r\n \
#ThisPhoneCompany really let me down... my new phone won%27t even turn on.' 'https://gateway.watsonplatform.net/tone-analyzer/api/v3/tone?version=2017-09-21&sentences=true'
You need to send "query" parameter for querystring. Pleaes check the below codes:
$toneAnalyserResponse = $client->request('POST', 'tone-analyzer/api/v3/tone', [
'auth' => ['{username}', '{password}'],
'headers' => [
'Content-Type' => 'text/plain',
],
'query' => [
'version' => '2017-09-21'
]
]);

Guzzle post json data causing 400 bad request

I am trying to use guzzle to do a post request to an open API. I am also sending the post data as follows. For some reason i am getting a 400 bad request
$req = $client->request('POST',$this->base_url.'nutrients?app_id='.$this->app_id.'&app_key='.$this->api_key,[
'headers' => [
'Content-Type' => 'application/json'
],
\GuzzleHttp\RequestOptions::JSON => [
"yield" => $portions,
"ingredients" => [
"quantity" => $portions,
"measureURI" => "\"$f_uri\"",
"foodURI" => "\"$m_uri\""
]
]
]);
$response = $client->send($req);
$decoded = json_decode($response->getBody());
dd($decoded);
The api documentation shows the method in curl as follows:
curl call:
curl -d #food.json -H "Content-Type: application/json" "https://api.edamam.com/api/food-database/nutrients?app_id=${YOUR_APP_ID}&app_key=${YOUR_APP_KEY}"
food.json:
{
"yield": 1,
"ingredients": [
{
"quantity": 1,
"measureURI": "http://www.edamam.com/ontologies/edamam.owl#Measure_unit",
"foodURI": "http://www.edamam.com/ontologies/edamam.owl#Food_11529"
}
]
}
My links for measureURI and foodURI are generated correctly.
You don't need to do ->send() after the ->request(), it already returns an instance of ResponseInterface.
So just
$response = $client->request('POST', $this->base_url.'nutrients?app_id='.$this->app_id.'&app_key='.$this->api_key, [
// ...
]
]);
$decoded = json_decode($response->getBody()->getContents());

convert JSON to guzzle php librairy request

I'm trying to covert a curl to guzzle request, here is the curl request.
curl https://{subdomain}.zendesk.com/api/v2/tickets.json \
-d '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}' \
-H "Content-Type: application/json" -v -u {email_address}:{password} -X POST
here is the JSON portion:
{
"ticket": {
"requester": {
"name": "The Customer",
"email": "thecustomer#domain.com"
},
"subject": "My printer is on fire!",
"comment": {
"body": "The smoke is very colorful."
}
}
}
Here is my broken PHP code.
$client = new GuzzleHttp\Client();
$res = $client->post('https://midnetworkshelp.zendesk.com/api/v2/tickets/tickets.json', [
'query' => [
'ticket' => ['subject' => 'My print is on Fire'], [
'comment' => [
'body' => 'The smoke is very colorful'] ], 'auth' => ['email', 'Password']]);
echo $res->getBody();
I keep getting access unauthorized for the user, however when I fire the curl command it works fine.
Any idea on what I'm possibly missing here?
Thank you
Ref:
http://curl.haxx.se/docs/manpage.html
http://guzzle.readthedocs.org/en/latest/clients.html
https://github.com/guzzle/log-subscriber
http://guzzle.readthedocs.org/en/latest/clients.html#json
Your biggest issue is that you are not converting your curl request properly.
-d = data that is being posted. In other words this is the body of your request.
-u = the username:pw that is being used to authenticate your request.
-H = extra headers that you want to use within your request.
-v = verbose output.
-X = specifies the request method.
I would recommend instanciating your client as follows:
$client = new GuzzleHttp\Client([
'base_url' => ['https://{subdomain}.zendesk.com/api/{version}/', [
'subdomain' => '<some subdomain name>',
'version' => 'v2',
],
'defaults' => [
'auth' => [ $username, $password],
'headers' => ['Content-Type' => 'application/json'], //only if all requests will be with json
],
'debug' => true, // only for debugging purposes
]);
This will:
Ensure that multiple subsequent requests made to the api will have the authentication information. Saving you from having to add it to each and every request.
Ensure that multipl subsequent (actually all) requests made with this client will contain the specified header. Saving you from having to add it to each and every request.
Provides some degree of future proofing (moving subdomain and api version into editable fields).
If you choose to log your request and response objects you can also do:
// You can use any PSR3 compliant logger in space of "null".
// Log the full request and response messages using echo() calls.
$client->getEmitter()->attach(new GuzzleHttp\Subscriber\Log\LogSubscriber(null, GuzzleHttp\Subscriber\Log\Formatter::DEBUG);
Your request will then simply become:
$json = '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}';
$url = 'tickets/tickets.json';
$request = $client->createRequest('POST', $url, [
'body' => $json,
]);
$response = $client->send($request);
or
$json = '{"ticket": {"subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}';
$url = 'tickets/tickets.json';
$result = $client->post(, [
'body' => $json,
]);
Edit:
After futher reading Ref 4 more thouroughly it should be possible to do the following:
$url = 'tickets/tickets.json';
$client = new GuzzleHttp\Client([
'base_url' => ['https://{subdomain}.zendesk.com/api/{version}/', [
'subdomain' => '<some subdomain name>',
'version' => 'v2',
],
'defaults' => [
'auth' => [ $username, $password],
],
'debug' => true, // only for debugging purposes
]);
$result = $client->post($url, [
'json' => $json, // Any PHP type that can be operated on by PHP’s json_encode() function.
]);
You shouldn't be using the query parameter, as you need to send the raw json as the body of the request (Not in parameters like you are doing.) Check here for information on how to accomplish this. Also, be sure to try to enable debugging to figure out why a request isn't posting like you want. (You can compare both curl and guzzles debug output to verify they match).

Categories