How to set isBase64Encoded: True in laravel response - php

I'm building an application on Laravel 8 and hosting the app on AWS lambda. I want to compress the response with gzip to HTTP request. I had interaction with AWS support and they asked me to add headers with 'Content-Encoding' => 'gzip', and also add isBase64Encoded to true. To achieve this I tried finding out the solution over the internet I found out a documentation for Laravel Vapor which handles this perfectly. They made an middleware which adds these attributes:
$response = $next($request);
if (in_array('gzip', $request->getEncodings()) && function_exists('gzencode')) {
$response->setContent(gzencode($response->getContent(), 9));
$response->headers->add([
'Content-Encoding' => 'gzip',
'X-Vapor-Base64-Encode' => 'True',
]);
}
return $response;
My current header looks like:
Since I'm not using Laravel Vapor So I need to put isBase64Encoded into the header:
I tried executing this via:
$response = $next($request);
if (in_array('gzip', $request->getEncodings()) && function_exists('gzencode')) {
$response->setContent(gzencode($response->getContent(), 9));
$response->headers->add([
'Content-Encoding' => 'gzip',
]);
$response->isBase64Encoded = true;
dd($response);
}
return $response;
As you can see I'm trying to add attribute by $response->isBase64Encoded = true;, once implemented the header changes to something unexpected:
Also the content is not encoded. Help me out in adding the isBase64Encoded attributes in response

Related

Wordpress REST API Caching Issue - WP Engine

I have created a custom plugin that actually just registeres a few API endpoints.
Right now the issue I'm having is that all of the endpoints are working fine locally, but when I push this code to WpEngine where I've hosted my WordPress site the API responses are getting cached.
If I clear the cache through WPEngine and make the request again the API is working fine until a 200 success response is received for the first time, once success is received then from the point the endpoint is always returning the same response no matter what header, parameter value I give to that endpoint.
In the wp-config.php file I've disabled the cache - define( 'WP_CACHE', false );
also tried adding
wp_cache_flush();
nocache_headers();
in the request action call back functions too, still no success, always the response are cached.
Few Code snippets for your reference -
// This is the route I've registered
public function register_routes()
{
register_rest_route($namespace, '/config' ,[
'methods' => 'GET',
'callback' => array($this, 'Action_GetConfig'),
'permission_callback' => 'authCheck'
]);
}
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
function Action_GetConfig(WP_REST_Request $request)
{
try {
// wp_cache_flush();
// nocache_headers();
$headers = $request->get_headers();
// Basic Validation
if (IsNullOrEmptyString($headers['platform'][0]) or IsNullOrEmptyString($headers['version'][0])) {
$resp = new WP_HTTP_Response();
// $resp->set_headers( array('Cache-Control' => 'no-cache, must-revalidate, max-age=0'));
$resp->set_status(400);
return $resp;
}
// Service Invocation
$results = $this->getConfig($headers['platform'][0], $headers['version'][0]);
$resp = new WP_HTTP_Response($results);
$resp->set_status(200);
return $resp;
} catch (Throwable $e) {
//$log->error($e);
$resp = new WP_HTTP_Response($e);
$resp->set_status(500);
return $resp;
}
}
Can someone help in solving this API response caching issue? Thanks!
I believe WP ENGINE USES, WP Engine MU PLUGIN. If so with this plugin you will have access to a few functions called
wpecommon::purge_varnish_cache()
, if you pass the ID of a particular post that you were targeted for, this function will clear the post cache. But if you use the function without passing the ID then it will clear all the cache of the entire domain( I would certainly not recommend this way, as it will cause a performance issue on a large site).
function your_call_of_action(WP_REST_Request $request){
$id = $request->get_param( 'id' );
if ( FALSE === get_post_status( $id ) ) {
$resp = new WP_HTTP_Response([]);
$resp->set_status(500);
return $resp;
}
wpecommon::purge_varnish_cache( $id )
// rest of your code goes here
}
Also, you can call the following API to clear the cache :
/installs/{install_id}/purge_cache
Read the following documents:
Read this document: https://wpengine.com/support/cache/
API Document: https://wpengineapi.com/reference
I solved this issue by adding a Cache Exclusion Policy in WPEngine. Because by default in WPEngine all the Endpoints responses are cached. So if we want NOT to cache a specific route, then we have to add that route to the Exclusion list.
path: ^/wp-json/nx/services/?
I added this above Route RegEx in WPEngine.

Symfony 5.* + Guzzle : cookies persistence

I'm currently developping an application in Symfony using Guzzle. I succesfully created a service where I make my requests (one request to get a list of enterprises, another to get user infos, ...) but I have issues regarding cookies in Guzzle. I've got to say I'm a newbie regarding API so I'm learning as I read the documentation but found nothing interesting for the moment. I've tried everything found on the internet so far but didn't get the result I wanted.
When I make a request, I get a property "Set-Cookie" in my response that I need to put in my next requests. The "Set-Cookie" property is something like "EfficySession=XX-XXXXX~XXXXXXXX-XXXXXXXX; path=/crm/; expires=Wed, 13 Oct 2021 23:22:14 GMT; HttpOnly".
So far this is where I am :
I create my client in the construct in order to be able to use the same client in every method :
public function __construct()
{
$this->client = new Client(["base_uri" => "BASE_URI", "allow_redirect" => true]);
}
And this is my test request to try setting my cookies right :
public function testFunction()
{
$json = json_encode([
[
"#name" => "api",
"#func" => [
[
"#name" => "currentuserfullname"
]
]
]
]);
$jar = new CookieJar();
$headers = [
'X-Efficy-ApiKey' => $this->apiKey,
'X-Efficy-Logoff' => 'false',
'Content-Type' => 'application/json'
];
$options = ["headers" => $headers, "body" => $json, "cookies" => $jar];
$response = $this->client->request('GET', 'json', $options);
$cookieParser = new SetCookie();
$cookie = $cookieParser->fromString($response->getHeader("Set-Cookie")[0]);
$cookie->setDomain('DOMAIN');
$this->jar->setCookie($cookie);
return json_decode($response->getBody()->getContents())[0]->{'#func'}[0];
}
But my cookies doesn't seem to be stored since I always get the property "Set-Cookie" in my response's headers... I think I've tried everything, from using SessionCookieJar to using CookieJar but nothing seems to be working.
Maybe I don't understand things the right way but as I said above, I'm just starting with API so sorry if you see big mistakes in my code.

Can't Use on_stats Option Using Laravel HTTP Client

Currently, I'm using Laravel HTTP client to make a request to an external URL. Mostly, the package working fine until I try to implement on_stats option from Guzzle.
From the doc, it says we can use Guzzle options using withMethod() method.
Here is my sample code to implement on_stats option using HTTP client.
$response = Http::withOptions([
'debug' => true,
'on_stats' => function(\GuzzleHttp\TransferStats $stats) {
Log::debug($stats->getTransferTime());
}
])
->get('https://laravel.com');
dd($response->status());
The code above will produce an error with the message:
Second array member is not a valid method
However, when I'm using the option within the Guzzle package directly, it works fine.
$client = new \GuzzleHttp\Client;
$response = $client->get('https://laravel.com', [
'on_stats' => function(\GuzzleHttp\TransferStats $stats) {
Log::debug($stats->getTransferTime());
}
]);
dd((string) $response->getStatusCode());
Any idea why this is happening? Is it a bug from the HTTP client wrapper from Laravel?
FYI, I'm using Laravel 8.x.
Thanks.
withOptions uses this code:
return tap($this, function ($request) use ($options) {
return $this->options = array_merge_recursive($this->options, $options);
});
So I'm guessing passing a closure in may not work, since it's not actually an array. From https://laracasts.com/discuss/channels/requests/httpwithtoken-get-total-time-of-request , you can get it from the response instead, so try this:
$client = new \GuzzleHttp\Client;
$response = $client->get('https://laravel.com');
Log::debug($response->transferStats->getTransferTime());

Doing HTTP requests FROM Laravel to an external API

What I want is get an object from an API with a HTTP (eg, jQuery's AJAX) request to an external api. How do I start? I did research on Mr Google but I can't find anything helping.
Im starting to wonder is this is even possible?
In this post Laravel 4 make post request from controller to external url with data it looks like it can be done. But there's no example nor any source where to find some documentation.
Please help me out?
Based upon an answer of a similar question here:
https://stackoverflow.com/a/22695523/1412268
Take a look at Guzzle
$client = new GuzzleHttp\Client();
$res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
echo $res->getStatusCode(); // 200
echo $res->getBody(); // { "type": "User", ....
We can use package Guzzle in Laravel, it is a PHP HTTP client to send HTTP requests.
You can install Guzzle through composer
composer require guzzlehttp/guzzle:~6.0
Or you can specify Guzzle as a dependency in your project's existing composer.json
{
"require": {
"guzzlehttp/guzzle": "~6.0"
}
}
Example code in laravel 5 using Guzzle as shown below,
use GuzzleHttp\Client;
class yourController extends Controller {
public function saveApiData()
{
$client = new Client();
$res = $client->request('POST', 'https://url_to_the_api', [
'form_params' => [
'client_id' => 'test_id',
'secret' => 'test_secret',
]
]);
echo $res->getStatusCode();
// 200
echo $res->getHeader('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// {"type":"User"...'
}
You just want to call an external URL and use the results? PHP does this out of the box, if we're talking about a simple GET request to something serving JSON:
$json = json_decode(file_get_contents('http://host.com/api/stuff/1'), true);
If you want to do a post request, it's a little harder but there's loads of examples how to do this with curl.
So I guess the question is; what exactly do you want?
As of Laravel v7.X, the framework now comes with a minimal API wrapped around the Guzzle HTTP client. It provides an easy way to make get, post, put, patch, and delete requests using the HTTP Client:
use Illuminate\Support\Facades\Http;
$response = Http::get('http://test.com');
$response = Http::post('http://test.com');
$response = Http::put('http://test.com');
$response = Http::patch('http://test.com');
$response = Http::delete('http://test.com');
You can manage responses using the set of methods provided by the Illuminate\Http\Client\Response instance returned.
$response->body() : string;
$response->json() : array;
$response->status() : int;
$response->ok() : bool;
$response->successful() : bool;
$response->serverError() : bool;
$response->clientError() : bool;
$response->header($header) : string;
$response->headers() : array;
Please note that you will, of course, need to install Guzzle like so:
composer require guzzlehttp/guzzle
There are a lot more helpful features built-in and you can find out more about these set of the feature here: https://laravel.com/docs/7.x/http-client
This is definitely now the easiest way to make external API calls within Laravel.
Updated on March 21 2019
Add GuzzleHttp package using composer require guzzlehttp/guzzle:~6.3.3
Or you can specify Guzzle as a dependency in your project's composer.json
{
"require": {
"guzzlehttp/guzzle": "~6.3.3"
}
}
Include below line in the top of the class where you are calling the API
use GuzzleHttp\Client;
Add below code for making the request
$client = new Client();
$res = $client->request('POST', 'http://www.exmple.com/mydetails', [
'form_params' => [
'name' => 'george',
]
]);
if ($res->getStatusCode() == 200) { // 200 OK
$response_data = $res->getBody()->getContents();
}
Definitively, for any PHP project, you may want to use GuzzleHTTP for sending requests.
Guzzle has very nice documentation you can check here.
I just want to say that, you probably want to centralize the usage of the Client class of Guzzle in any component of your Laravel project (for example a trait) instead of being creating Client instances on several controllers and components of Laravel (as many articles and replies suggest).
I created a trait you can try to use, which allows you to send requests from any component of your Laravel project, just using it and calling to makeRequest.
namespace App\Traits;
use GuzzleHttp\Client;
trait ConsumesExternalServices
{
/**
* Send a request to any service
* #return string
*/
public function makeRequest($method, $requestUrl, $queryParams = [], $formParams = [], $headers = [], $hasFile = false)
{
$client = new Client([
'base_uri' => $this->baseUri,
]);
$bodyType = 'form_params';
if ($hasFile) {
$bodyType = 'multipart';
$multipart = [];
foreach ($formParams as $name => $contents) {
$multipart[] = [
'name' => $name,
'contents' => $contents
];
}
}
$response = $client->request($method, $requestUrl, [
'query' => $queryParams,
$bodyType => $hasFile ? $multipart : $formParams,
'headers' => $headers,
]);
$response = $response->getBody()->getContents();
return $response;
}
}
Notice this trait can even handle files sending.
If you want more details about this trait and some other stuff to integrate this trait to Laravel, check this article. Additionally, if interested in this topic or need major assistance, you can take my course which guides you in the whole process.
I hope it helps all of you.
Best wishes :)
Basic Solution for Laravel 8 is
use Illuminate\Support\Facades\Http;
$response = Http::get('http://example.com');
I had conflict between "GuzzleHTTP sending requests" and "Illuminate\Http\Request;" don't ask me why... [it's here to be searchable]
So looking for 1sec i found in Laravel 8 Doc...
**Guzzle is inside the Laravel 8 Http Request !**
https://laravel.com/docs/8.x/http-client#making-requests
as you can see
https://laravel.com/docs/8.x/http-client#introduction
Laravel provides an expressive, minimal API around the Guzzle HTTP
client, allowing you to quickly make outgoing HTTP requests to
communicate with other web applications. Laravel's wrapper around
Guzzle is focused on its most common use cases and a wonderful
developer experience.
It worked for me very well, have fun and if helpful point up!
I also created trait similar to #JuanDMeGonthat's that u can use anywhere in your project.Please check this out
trait ApiRequests
{
public function get($url, $data = null)
{
try {
$response = Http::get($this->base_url . $url, $data);
} catch (\Exception $e) {
info($e->getMessage());
abort(503);
}
if ( $response->status() == 401) {
throw new AuthenticationException();
} else if (! $response->successful()) {
abort(503);
}
return $response->json();
}
public function post($url, $data = [])
{
$token = session()->get('token');
try {
$response = Http::acceptJson()->withToken($token)->post($this->base_url . $url, $data);
} catch (\Exception $e) {
abort(503);
}
if ($response->status() == 401 && !request()->routeIs('login')) {
throw new AuthenticationException();
}
return $response;
}
}
class Controller extends BaseController
{
protected $base_url;
use AuthorizesRequests, DispatchesJobs, ValidatesRequests, ApiRequests;
public function __construct()
{
$this->base_url = env("BASE_URL","http://192.168.xxxxxxx");
View::share('base_url', $this->base_url);
}
}
You can use Httpful :
Website : http://phphttpclient.com/
Github : https://github.com/nategood/httpful
Here is the simple call for laravel 9.4
Route::get('/currency', function () {
$response = Http::withHeaders([
'x-api-key' => 'prtl6749387986743898559646983194',
])->get('https://partners.api.skyscanner.net/apiservices/v3/culture/currencies');
return response()->json(['status'=> true,'data'=> json_decode($response->body()), 'Message'=>"Currency retrieved successfully"], 200);
});
Don't forget to import
use Illuminate\Support\Facades\Http;

Laravel - POST data is null when using external request

I'm new to laravel, and I'm trying to implement a simple rest api.
I have the controller implemented, and tested via unit testing.
My problem is with the POST request.
Via the tests Input:json has data, via an external rest client it returns null.
This is the code on the unit test
$newMenu = array(
'name'=>'Christmas Menu',
'description'=>'Christmas Menu',
'img_url'=>'http://www.example.com',
'type_id'=>1,
);
Request::setMethod('POST');
Input::$json = $newMenu;
$response = Controller::call('menu#index');
What am I doing wrong?
UPDATE:
This is realy driving me crazy
I've instanciated a new laravel project and just have this code:
Routes
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Controller:
class Home_Controller extends Base_Controller {
public $restful = true;
public function get_index()
{
return Response::json(['test'=>'hello world']);
}
public function post_index()
{
return Response::json(['test'=>Input::all()]);
}
}
CURL call:
curl -H "Accept:application/json" -H"Content-type: application/json" -X POST -d '{"title":"world"}' http://localhost/laravel-post/public/test
response:
{"test":[]}
Can anyone point me to what is wrong.
This is really preventing me to use laravel, and I really liked the concept.
Because you are posting JSON as your HTTP body you don't get it with Input::all();
You should use:
$postInput = file_get_contents('php://input');
$data = json_decode($postInput, true);
$response = array('test' => $data);
return Response::json($response);
Also you can use
Route::any('test', 'home#index');
instead of
Route::get('test', 'home#index');
Route::post('test', 'home#index');
Remove header Content-type: application/json if you are sending it as key value pairs and not a json
If you use : Route::post('test', 'XYZController#test');
Send data format : Content-type : application/json
For example : {"data":"foo bar"}
And you can get the post (any others:get, put...etc) data with :
Input::get('data');
This is clearly written in here : http://laravel.com/docs/requests
. Correct Content-type is very important!
I am not sure your CURL call is correct. Maybe this can be helpful : How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
I am using Input::get('data') and it works.
I was facing this problem, my response of post was always null. To solve that I put the body key in guzzle object, like this
$client = new Client([
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => config('app.callisto_token'),
]
]);
$body = [
'firstResult'=> 0,
'data' => '05/05/2022'
];
$response = $client->post('http://'.$this->ip.'/IntegracaoERP'.'/status_pedido',
['body' => json_encode($body)]
);
Don't forget the json_encode in body key.
Hope this helps.

Categories