I have been using the HTTP client in Laravel 8, as follows:
$http = Http::asForm()->post($url, $post_data);
$response = $http->body();
This works great. Now I want to include a file upload as part of this request, but the file is optional. I have tried to structure my request like this:
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;
public function index(Request $request)
{
$url = 'my-url';
$post_data = $request->post();
$http = Http::asForm();
if ($request->hasFile('image')) {
$http->attach('image', $request->file('image'));
}
$http->post($url, $post_data);
$response = $http->body();
}
But this is not working. The error I am getting is: Method Illuminate\Http\Client\PendingRequest::body does not exist.
The post() method appears to be returning Illuminate\Http\Client\PendingRequest instead of Illuminate\Http\Client\Response.
Any ideas how to do this?
$response = $http->post($url, $post_data)->body();
// alternatively:
$pendingRequest = $http->post($url, $post_data);
$response = $pendingRequest->body();
In your second code sample, you don't assign the return of post() to a variable. But this return value (Illuminate\Http\Client\PendingRequest) is the object that defines the body() method. So either use a second variable (or reassign $http), or chain the post() and body() calls as shown above.
Related
in vanilla php i would create a callbak url with just
try
{
//response content type application/json
header("Content-Type:application/json");
//read incoming request
$postData = file_get_contents('php://input');
.......
......
but in laravel i'm yet to get a clear explanation on how to achieve the same
ive tried using
$postData = Request::getContent();
but it returns blank
If you need data in request use (new \Illuminate\Http\Request())->all() or use DI
public function someAction(\Illuminate\Http\Request $request)
{
dd($request->all());
}
I'm trying to access an uploaded file in the history middleware for Guzzle (v6).
My actual code receives a request (so is using the ServerRequestInterface), then uses Guzzle to send the request elsewhere.
I'm trying to test uploaded files going through this layer, but I can't seem to access them in the Request object returned by Guzzle's middleware.
Example code:
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\ServerRequest;
use GuzzleHttp\Psr7\UploadedFile;
class DoNotCommitTest extends \PHPUnit\Framework\TestCase
{
public function testUploads()
{
$request = new ServerRequest('GET', 'http://example.com/bla');
$file = new UploadedFile('test', 100, \UPLOAD_ERR_OK);
$request = $request->withUploadedFiles([$file]);
$this->assertCount(1, $request->getUploadedFiles());
// Mock Guzzle request, assert on the request it 'sent'
$mock = new MockHandler([
function (ServerRequest $request, array $options) {
// This fails...
$this->assertCount(1, $request->getUploadedFiles());
}
]);
$historyContainer = [];
$history = Middleware::history($historyContainer);
$handler = HandlerStack::create($mock);
$handler->push($history);
$client = new Client(['handler' => $handler]);
$client->send($request);
}
}
If you follow execution chain, $client->send($request) at some point calls private applyOptions function, which calls Psr7\modify_request function. If you look at Psr7\modify_request function:
...
if ($request instanceof ServerRequestInterface) {
return new ServerRequest(
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
$uri,
$headers,
isset($changes['body']) ? $changes['body'] : $request->getBody(),
isset($changes['version'])
? $changes['version']
: $request->getProtocolVersion(),
$request->getServerParams()
);
}
...
It returns new ServerRequest object without preserving your uploaded files array (ServerRequest object doesn't have the uploadedFiles as an argument in the constructor). That's why you lost your uploadedFiles array.
UPDATE:
I created an issue and a pull request to fix it.
I am in a confusing situation
In my Laravel controller, I have a variable
public function storeName($key)
$store = new Store();
$storeName = $store->connectAPI($key);
This $storeName variable will actually give me a URL, which if accessed, will give me a JSON response.
If I die and dump $storeName variable it will print
http://store123.com?key=2093983892
But, what I actually want is to access this $storeName variable, by passing a GET request in my controller, so I can get a JSON response from this API call.
How can I access this URL in my controller?
From Guzzle docs
$client = new GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.github.com/user', []);
if($res->getStatusCode())
{
// "200"
$json = $res->getBody();
}
I used json_decode inside a curl_init function to solve this issue.
I need to make a route in a Symfony 3 app (server 1), which has to send a (filtered) request on a server 2, then send back the exact response given by the server 2 (same HTTP status code, headers and body).
With the native curl Php library, you can get the raw response (including headers), by setting the CURLOPT_HEADER option to True.
But the Response object from Symfony HttpFoundation seems to be only configurable by setting separately headers (inside the constructor, or with $response->headers->set()) and body (with $response->setContent(). I didn't find a way to set a raw response (with headers) into the Response object.
Is it possible, or how could it be done otherwise?
Here's my try:
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyController extends Controller
{
/**
* #Route("/get", name="get")
*/
public function getAction(Request $request)
{
// Filter/modify the query string, but keep it quite similar:
$request->query->remove('some_private_attr');
$my_query_string = http_build_query($request->query->all());
// Setup the curl request:
$curl = curl_init('http://localhost?'.$my_query_string);
curl_setopt($curl, CURLOPT_HEADER, 1); // Include headers
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Return data as a string
curl_setopt($curl, CURLOPT_PORT, 8200);
// Perform the request, returning the raw response
// (headers included) as a string:
$result = curl_exec($curl);
// Get the response status code:
$status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// Here, how can I pass the raw external response ($result)
// to a new Response object, without parsing the header
// and body parts unnecessarily?
// Of course, the following doesn't send the right headers:
$response = new Response($result, $status_code);
return $response;
}
}
You should be able to use (for example):
$response->headers->set('Content-Type', 'text/plain');
which is described here:
http://symfony.com/doc/current/components/http_foundation.html#response
The Response API also describes each of the methods. I'm not certain what type of header you need to send.
I had the exact same issue. I basically wanted to forward the CurlResponse as a Response by the controller.
I implemented this as follows, using the standard Symfony HttpClient:
public function myAction()
{
/** #var Request $request */
$request = $this->container->get('request_stack')->getCurrentRequest();
$my_query_string = http_build_query($request->query->all());
$client = HttpClient::create();
$url = 'http://localhost?'.$my_query_string;
$response = $client->request('GET', $url);
$statusCode = $response->getStatusCode();
$headers = $response->getHeaders();
$content = $response->getContent();
return new JsonResponse($content, $statusCode, $headers);
}
If your content is already Json, add the optional parameter true to JsonResponse.
I'm going to write some Symfony2 UnitTests (derived from Symfony\ Bundle\ FrameworkBundle\ Test\ WebTestCase) to test ajax controllers, similar to this How to get Ajax post request by symfony2 Controller.
My big problem is to get the parameters into the "request" bag of the request, not into the "parameter" bag. Similar to the upper example the method in the controller looks like this:
public function ajaxAction(Request $request)
{
$data = $request->request->get('data');
}
But if i do a var_dump of the $request, the paramaters i supply in the WebTestCase do not appear in $request->request, but in $request->parameter. Let's say this is the portion of code in my webtestcase:
....
$client = static::createClient();
$client->request('POST', '/ajax/blahblah', ... ?????);
I already tried supplying the parameter(s) directly within the url as
/ajax/blahblah?data=whocares
I tried specifying the parameter within an array
$client->request('POST', '/ajax/blahblah', array('data' => 'fruityloops'));
But nothing worked. Any chance to get this running?
Thanks in advance
Hennes
After you make the request, you need to get the response. Try this:
$client = static::createClient();
$client->request('POST', '/ajax/blahblah', array('data' => 'fruityloops'));
$response = $client->getResponse();
$this->assertEquals(200, $response->getStatusCode());
//convert to array
$data = json_decode($response->getContent(true), true);
var_dump($data);
$this->assertArrayHasKey('your_key', $data);