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).
Related
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;
}
I cannot attach the uploaded file. I see that fopen($image->getPathname(),'r') returns not convertible json data type making guzzle return error json_encode error: Type is not supported. What am I doing wrong here? Thank you.
stream resource #586 ▼
timed_out: false
blocked: true
eof: false
wrapper_type: "plainfile"
stream_type: "STDIO"
mode: "r"
unread_bytes: 0
seekable: true
uri: "\Temp\php2D41.tmp"
options: []
//use Illuminate\Support\Facades\Http;
//use Illuminate\Support\Facades\File;
if($request->hasFile('imgInp1'))
{
foreach(request('imgInp1') as $image)
{
$message = Http::post('https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token,
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
'multipart' => [
'name' => 'image',
'image_path' => $image->getPathname(),
'image_mime' => $image->getmimeType(),
'image_org' => $image->getClientOriginalName(),
'contents' => fopen($image->getPathname(), 'r'),
],
'message'=>[
'attachment' => [
'type' => 'image',
'payload' => [
"is_reusable"=> true,
],
],
],
]);
}
}
From the url you used this is the curl request provided in facebook api_guide
curl \
-F 'message={"attachment":{"type":"image", "payload":{"is_reusable":true}}}' \
-F 'filedata=#/tmp/shirt.png;type=image/png' \
"https://graph.facebook.com/v9.0/me/message_attachments?access_token=<PAGE_ACCESS_TOKEN>"
This is what -F means in curl
-F, --form <name=content>
(HTTP SMTP IMAP) For HTTP protocol family, this lets curl emu‐
late a filled-in form in which a user has pressed the submit
button. This causes curl to POST data using the Content-Type
multipart/form-data according to RFC 2388.
(Source: man curl)
By interpreting second line of curl,
You can also tell curl what Content-Type to use by using
'type=', in a manner similar to:
curl -F "web=#index.html;type=text/html" example.com
or
curl -F "name=daniel;type=text/foo" example.com
So it tells that you need multipart/form-data.
I am using guzzle directly inplace of using HttpClient(comes by default in laravel, comfirm from composer.json). Also I suggest to use try catch block as it is not necessary that it will always be 200 response.
$message["attachment"] = [
"type" => "image",
"payload"=> ["is_reusable"=>true]
];
try{
$client = new \GuzzleHttp\Client();
if(file_exists($image)){ // or can use \Illuminate\Support\Facades\File::exists($image)
$request = $client->post( 'https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token, [
// 'headers' => [], //if you want to add some
'multipart' => [
[
'name' => 'message',
'contents' => json_encode($message),
],
[
'Content-type' => $image->getmimeType(),
'name' => 'filedata',
'contents' => fopen($image->getPathname(), 'r'),
]
]
]);
if ($request->getStatusCode() == 200) {
$response = json_decode($request->getBody(),true);
//perform your action with $response
}
}else{
throw new \Illuminate\Contracts\Filesystem\FileNotFoundException();
}
}catch(\GuzzleHttp\Exception\RequestException $e){
// see this answer for https://stackoverflow.com/questions/17658283/catching-exceptions-from-guzzle/64603614#64603614
// you can catch here 400 response errors and 500 response errors
// see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
}catch(Exception $e){
//catch other errors
}
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.)
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);
}
I have a problem with translating curl to guzzle request.
In docs to create a user i just need to post:
$ curl -XPOST -d '{"username":"test", "password":"super_secret_password"}' -H "Content-Type:application/json" -u "$CLOUDMQTT_USER:$CLOUDMQTT_PASSWORD" https://api.cloudmqtt.com/user
In my project I cannot use curl, so i use guzzle:
$client = new Client();
$res = $client->post('https://api.cloudmqtt.com/user', ['auth' => ['xxx', 'xxx'], 'body' => ["username"=>"user", "password"=>"super_secret_password"]]);
And user is created, I can see new user on the users list on panel, but server is responsing with 500 when creating the user. What am I doing wrong? Maybe my guzzle request is wrong format? I have no idea
https://www.cloudmqtt.com/docs-api.html link to API
This will match up your Guzzle request to the curl request, although I can't say for sure that will solve your 500 error:
$client = new Client([
'headers' => [ 'Content-Type' => 'application/json' ]
]);
$response = $client->post('https://api.cloudmqtt.com/user',
[
'auth' => ['xxx', 'xxx'],
'body' => json_encode(
[
"username"=>"user",
"password"=>"super_secret_password"
]
)
]
);
The differences here include setting the Content-Type header and also encoding the body to json instead of an array (which may not have an effect here?).
EDIT:
It looks like the json parameter will automatically set the header and json_encode the body for you:
$client = new Client();
$response = $client->post('https://api.cloudmqtt.com/user',
[
'auth' => ['xxx', 'xxx'],
'json' =>
[
"username"=>"user",
"password"=>"super_secret_password"
]
]
);
Docs