Getting API Response using Guzzle in Laravel - php

I am trying to get a response from the Metals API but keep getting 404 errors even though I can get the API using the URL.
public function valueFromApi(){
$accesskey = "123456";
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://metals-api.com/api/latest', [
'form_params' => [
'access_key' => $accesskey,
'base' => 'GBP',
'symbols' => 'XAU',]
]);
dd($response);
}
If I try and access the URL directly through a browser this works:
https://metals-api.com/api/latest?access_key=123456&base=GBP&symbols=XAU
I must have misunderstood the way the parameters are working. Any advice is appreciated.

Form params is not the same as query parameters. Therefor you need to set the parameters as query. If you are accessing this in the browser, i would not expect it to be a POST but a GET.
$response = $client->request('GET', 'https://metals-api.com/api/latest', [
RequestOptions::QUERY => [
'access_key' => $accesskey,
'base' => 'GBP',
'symbols' => 'XAU',
]
]);
I am using the RequestOptions, this is syntaxic sugar for the hardcoded string options, the same as 'query'.

As specified in their docs, you need to define the constant
define("form_params", GuzzleHttp\RequestOptions::FORM_PARAMS );
Then you can use your code
$response = $client->request('POST', 'https://metals-api.com/api/latest', [
'form_params' => [
'access_key' => $accesskey,
'base' => 'GBP',
'symbols' => 'XAU',]
]);

Related

Trying to use Laravel HTTP to upload a file to a 3rd party

I have the following Postman request for testing a third party API;
What I am trying to do is convert this into code using Laravel's HTTP class, the code i currently have is;
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true,
'frontfile' => Storage::get('somefrontfile.jpg'),
'sideview' => Storage::get('itsasideview.png'),
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->asForm()
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
But every time I run this, the 3rd party API comes back with Invalid ID, even though if i use Postman with the same ID it works fine.
I cant seem to figure out where i am going wrong with my code;
As #Cbroe mention about attach file before sending post request you can make this like this example:
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->attach(
'frontfile', file_get_contents(storage_path('somefrontfile.jpg')), 'somefrontfile.jpg'
)
->attach(
'sideview', file_get_contents(storage_path('itsasideview.png')), 'itsasideview.jpg'
)
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
Also i think you need remove asForm method because it's override your header accept type to application/x-www-form-urlencoded that is way your exception is Invalid ID
Some third party API would require you to have the request with content type as multipart/form data
you can double check all the headers being pass on your postman request HEADERS tab and view on Hidden headers.
If you indeed need your request to be in multipart/form-data, You can use the multipart options of guzzle.
Although this doesnt seem to be on Laravel HTTP-Client docs, you can simply pass a asMultipart() method in your HTTP request
just check the /vendor/laravel/framework/src/Illuminate/Support/Facades/Http.php for full reference of HTTP client.
You can have your request like this.
public function uploadToThridParty() {
$uploadContents = [
[
'name' => 'id',
'contents' => 'this-is-my-id'
],
[
'name' => 'fileUpload',
'contents' => true
],
[
'name' => 'frontfile',
'contents' => fopen( Storage::path( 'somefrontfile.jpg' ), 'r')
],
[
'name' => 'sideview',
'contents' => fopen( Storage::path( 'itsasideview.jpg' ), 'r')
],
];
$request = Http::withHeaders(['Accept' => 'application/json']);
$response = $request->asMultipart()->post('https://urltoupload.com/upload', $uploadContents );
}

Get API response URL param using Guzzle HTTP request in Guzzle 7

I searched online but couldn't find a proper solution. I am calling a Spring service with a POST request using Guzzle Client, The service in case of any errors provides the error message in its URL param like: http://localhost:8085/fedauth/null?errMessage=Mot%20de%20passe%20invalide%20pour%20l'utilisateur%20Karan%20Sharma.. How can I fetch this param errMessage using Guzzle. Below is my code with Slim in PHP.
$data = [
'userName' => base64_encode($userName),
'userPassword' => base64_encode($userPassword),
'institution' => $institution,
'redirectUrl' => $redirectUrl,
'callerUrl' => $callerUrl,
'clientId' => $clientId,
'encryptMode' => $encryptMode,
'moodleLandPage' => $moodleLandPage,
'login' => $login,
'isEncrypted' => true
];
try {
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
} catch (Exception $exception) {
return $response->write(json_encode(['error' => $exception->getMessage(), "auth" => "0" ]));
}
I have tried using the getEffectiveUrl() method but its no longer supported in Guzzle 7
I guess you get the response as a redirect url? Your question is not clear in that point. In this case you can access it like this:
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getEffectiveUrl();
like here: https://docs.guzzlephp.org/en/5.3/http-messages.html#responses
Actually found the answer. You need to add track redirects option as true and then use $response->getHeaderLine('X-Guzzle-Redirect-History'); like below
$client = new GuzzleHttp\Client(['headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded'], 'verify' => false, 'allow_redirects' => ['track_redirects' => true]]);
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getHeaderLine('X-Guzzle-Redirect-History');

How can I use Guzzle to send a PUT request?

Does anybody know the correct way to PUT using Guzzle? my code is not working
but my post methods are working
$enrolment = $client->request('PUT', $url,[
'form_params' => [
'contactID' =>12345,
'type' =>'w'
],
'headers' => [
'apitoken' => $api_token,
'wstoken' => $ws_token
]
]);
resulted in a 500 Internal Server Error response:↵{"DATA":"","ERROR":true,"MESSAGES":"key [TYPE] doesn't exist","CODE":"0","DETAILS":""}
The PUT request does't accept form_params type as request option, so it may ignore the setting.
From Docs:
form_params
Used to send an application/x-www-form-urlencoded
POST request.
Maybe you can try using json for PUT request.
In the json part of Docs, it uses PUT as well.
$enrolment = $client->request('PUT', $url,[
'json' => [
'contactID' =>12345,
'type' =>'w'
],
'headers' => [
'apitoken' => $api_token,
'wstoken' => $ws_token
]
]);

Returning GuzzleHttp response object causes ERR_INVALID_CHUNKED_ENCODING in browser

I'm using guzzle 6 in laravel 5 to send a post request but I'm getting ERR_INVALID_CHUNKED_ENCODING when I try to access the request() in the method that handles the post request.
Here's my code:
Routes.php
Route::get('/guzzle', [
'as' => 'guzzle-test',
'uses' => 'TestController#getTest'
]);
Route::post('/guzzle', [
'as' => 'guzzle-post-test',
'uses' => 'TestController#postTest'
]);
TestController.php
public function getTest()
{
$client = new Client();
$data = [
'hey' => 'ho'
];
$request = $client->post(route('guzzle-post-test'), [
'content-type' => 'application/json'
], json_encode($data));
return $request;
}
public function postTest()
{
dd(getTest());
}
I getting to the post request handler since I've tried to diedump a string and it gets there, but if i call the request() I get that error. For what I've researched It may have something to with the content length, but after reading guzzle's docs and some stuff around the web I could find how to get and pass the content length appropriately in the request. Any help would be very appreciated!
First off, here's some test code which you should be able to adapt for your purposes (also see form_params in the docs for GuzzleHttp):
public function validateRecaptcha()
{
$client = new Client;
$response = $client->request('POST', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'secret' => env('RECAPTCHA_SECRET'),
'response' => Request::input('g-recaptcha-response'),
'remoteip' => Request::ip()
]
]);
return $response;
}
I just ran into the same issue and found that trying to return the response object in Laravel gave me ERR_INVALID_CHUNKED_ENCODING. Whereas, doing a dd() on the response itself showed me what I was actually wanting to see:
public function validateRecaptcha()
{
$client = new Client;
$response = $client->request('POST', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'secret' => env('RECAPTCHA_SECRET'),
'response' => Request::input('g-recaptcha-response'),
'remoteip' => Request::ip()
]
]);
dd($response);
}
Unfortunately, without doing further research, I'm unable to explain why ERR_INVALID_CHUNKED_ENCODING keeps coming up when I try to return the client library's objects to the browser, but my initial inclination is that it's a data type issue.
As far as your question goes, you're not actually trying to get back the "request" but rather the response. According to http://docs.guzzlephp.org/en/latest/quickstart.html#using-responses, if you want to get the API response contained in the response object (or at least in my case, I did), you'll want to use the getBody() method:
public function validateRecaptcha()
{
$client = new Client;
$response = $client->request('POST', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'secret' => env('RECAPTCHA_SECRET'),
'response' => Request::input('g-recaptcha-response'),
'remoteip' => Request::ip()
]
]);
return $response->getBody();
}
And then of course, if you expect it to be a JSON response (i.e. REST), then simply pass it to json_decode() to get your associative array back.
public function validateRecaptcha()
{
$client = new Client;
$response = $client->request('POST', 'https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'secret' => env('RECAPTCHA_SECRET'),
'response' => Request::input('g-recaptcha-response'),
'remoteip' => Request::ip()
]
]);
return json_decode($response->getBody(), true); // true = assoc. array
}
Hope that helps!

Can you include raw JSON in Guzzle POST Body?

This should be soo simple but I have spent hours searching for the answer and am truly stuck. I am building a basic Laravel application and am using Guzzle to replace the CURL request I am making at the moment. All the CURL functions utilise raw JSON variables in the body.
I am trying to create a working Guzzle client but the server is respsonding with 'invalid request' and I am just wondering if something fishy is going on with the JSON I am posting. I am starting to wonder if you can not use raw JSON in the Guzzle POST request body? I know the headers are working as I am receiving a valid response from the server and I know the JSON is valid as it is currently working in a CURL request. So I am stuck :-(
Any help would be sooo greatly appreciated.
$headers = array(
'NETOAPI_KEY' => env('NETO_API_KEY'),
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'NETOAPI_ACTION' => 'GetOrder'
);
// JSON Data for API post
$GetOrder = '{
"Filter": {
"OrderID": "N10139",
"OutputSelector": [
"OrderStatus"
]
}
}';
$client = new client();
$res = $client->post(env('NETO_API_URL'), [ 'headers' => $headers ], [ 'body' => $GetOrder ]);
return $res->getBody();
You can send a regular array as JSON via the 'json' request option; this will also automatically set the right headers:
$headers = [
'NETOAPI_KEY' => env('NETO_API_KEY'),
'Accept' => 'application/json',
'NETOAPI_ACTION' => 'GetOrder'
];
$GetOrder = [
'Filter' => [
'OrderID' => 'N10139',
'OutputSelector' => ['OrderStatus'],
],
];
$client = new client();
$res = $client->post(env('NETO_API_URL'), [
'headers' => $headers,
'json' => $GetOrder,
]);
Note that Guzzle applies json_encode() without any options behind the scenes; if you need any customisation, you're advised to do some of the work yourself
$res = $client->post(env('NETO_API_URL'), [
'headers' => $headers + ['Content-Type' => 'application/json'],
'body' => json_encode($getOrders, ...),
]);
Guzzle 7 Here
The below worked for me with raw json input
$data = array(
'customer' => '89090',
'username' => 'app',
'password' => 'pwd'
);
$url = "http://someendpoint/API/Login";
$client = new \GuzzleHttp\Client();
$response = $client->post($url, [
'headers' => ['Content-Type' => 'application/json', 'Accept' => 'application/json'],
'body' => json_encode($data)
]);
print_r(json_decode($response->getBody(), true));
For some reasons until I used the json_decode on the response, the output wasn't formatted.
You probably need to set the body mime type. This can be done easily using the setBody() method.
$request = $client->post(env('NETO_API_URL'), ['headers' => $headers]);
$request->setBody($GetOrder, 'application/json');

Categories