symfony perform post query - php

I need to perform post request using using Symfony framework. I can see there is package Symfony\Component\HttpFoundation\Request for this purpose. But when I create post request it seems doens't really perform request and return object data
$response = Request::create(get_api_url().'test','POST', $params);
How can I permorm real post request?

You can use
use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$response = $client->request('POST', 'https://...');
More details you can find here

Related

Creating a proxy in Laravel with Guzzle

I need to use an api in my website frontend, but I don't want to expose that api's key to my frontend users, so I've decided to make a proxy. However, I don't think I've necessarily done it in the most clean, straight-forward, Laravel-like or Guzzle-like way. I'll show my work:
In web.php I added a route that looks like this: Route::post('/address-api/{path?}', 'Controller#addressApi')->where('path', '.*'); That way, the entire path after /address-api is passed to my controller, so I can proxy hypothetically ANY post request to that api.
Then in Controller.php I've done this:
public function addressApi($path, Request $request)
{
if (!Str::startsWith($path, '/')) $path = '/' . $path; // make sure it starts with /
$url = 'https://api.craftyclicks.co.uk/address/1.1' . $path;
$postData = $request->all();
$postData['key'] = env('CRAFTYCLICKS_KEY');
$client = new Client();
$response = $client->request('POST', $url, [
'json' => $postData
]);
return response()->json(json_decode($response->getBody(), true));
}
So, whatever json they post to my api, I post to the CraftyClicks api, but I add our secret key to the json. The code above is working, it just doesn't seem like the right way to do it.
The thing I'm not sure about is json_decoding the body and returning it, return response()->json(json_decode($response->getBody(), true));. I feel like there's something... dirty about this. I feel like there must be a cleaner way to return the actual API response exactly as it came in.
At first I was doing return $response->getBody();, but I didn't like that because it didn't have the Content-type: application/json header in the response when I did it that way. Does Guzzle provide, out of the box, a way of just returning their response entirely as-is, headers and all?
Let Laravel have the output; this is cleaner.
return response($response->getBody())
->withHeaders($response->getHeaders());

Guzzle map response to object

Is there a way using Guzzle in PHP that when I make a request to an API call that I can map my response to a Response object?
So instead of having to get the response data and then passing my array value as an argument, Guzzle can automatically resolve it to the required class?
In essence, this is what I am doing:
$client = new GuzzleHttp\Client();
$response = $client->request('myapi.users', 'GET');
$responseData = $response->getBody()->getContents();
$user = new User($responseData);
However I would like to try and avoid that boilerplate code by doing something like the following:
$client = new GuzzleHttp\Client();
$user = $client->request('myapi.users', 'GET');
Does Guzzle allow you to map response objects to Responses?
Thanks!
Nope, an HTTP Client (which Guzzle is) is not responsible for that. That's why there is not such a function there.
You can use Guzzle and your own object mapper, BTW, and create an SDK for the API you are using. Like the GitHub SDK, for example, that also uses Guzzle inside, but provides a specific interface for the domain.

Remove specific cookie in Guzzle response

I would like to remove a specific cookie in a Guzzle response object.
My application uses Slim framework and I make calls to an API with Guzzle. Both Slim and Guzzle implement the Request and Response Interface (Psr7) so I can easily return a Guzzle response in a Slim controller like this :
class APIController {
public function call($request, $response) {
// Do stuff with $request (check body and params, change url, etc)
$client = new \GuzzleHttp\Client();
$response = $client->send($request, []);
return $response;
}
}
Everything works fine but the API returns a cookie I want to remove. I can remove the whole header with :
$response = $response->withoutHeader('Set-Cookie');
Is there a native way in Guzzle to remove a specific cookie by name instead of removing the whole header ?

Guzzlehttp - Correct way to get same callback called immediately when each request done

While using Guzzle for async requests, I want got same callback immediately when each request done.
Following code is works, but I think it's may not make sense.
Does Guzzle provide any method like Promise\settle($promises)->then($callback)->wait() but for each requests get done?
<?php
require("vendor/autoload.php");
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
$client = new Client(['base_uri' => 'http://httpbin.org/']);
// I want got callback immediately when each request done.
$callback = function($response) {
echo $response->getBody();
};
$promises = [
$client->getAsync('/delay/8')->then($callback),
$client->getAsync('/delay/4')->then($callback),
$client->getAsync('/delay/2')->then($callback),
$client->getAsync('/delay/1')->then($callback),
];
Promise\settle($promises)->wait();

How Follow the Don't Repeat Yourself Principle When Consuming My Own Laravel API?

I'm developing a Laravel 4 app that will make the same CRUD operations on my data set available through a JSON REST API and a Web UI. It seems that to prevent breaking the DRY principle that my UI should consume my own API by routing all requests from the UI back to the API. I'm unsure though about the best approach to making this work. Presumably I would have separate UI and API controllers and somehow route the requests through. Or should I be looking at a different approach altogether?
I'm actually tinkering with the same idea and it's pretty neat. With Laravel you do have the ability to make internal requests (some might refer to this as HMVC, but I won't). Here's the basics of an internal request.
$request = Request::create('/api/users/1', 'GET');
$response = Route::dispatch($request);
$response will now contain the returned response of the API. Typically this will be returned a JSON encoded string which is great for clients, but not that great for an internal API request. You'll have to extend a few things here but basically the idea is to return the actual object back through for the internal call, and for external requests return the formatted JSON response. You can make use of things like $response->getOriginalContent() here for this kind of thing.
What you should look at doing is constructing some sort of internal Dispatcher that allows you to dispatch API requests and return the original object. The dispatcher should also handle malformed requests or bad responses and throw exceptions to match.
The idea itself is solid. But planning an API is hard work. I'd recommend you write up a good list of all your expected endpoints and draft a couple of API versions then select the best one.
NOTE: As vcardillo pointed out below, route filters are not called with these methods.
I am currently doing the same thing, and Jason's answer got me going in a great direction. Looking at the Symfony\Component\HttpFoundation\Request documentation, I figured out how to POST, as well as everything else I'd need to do. Assuming you're using a form, here is some code that could help you:
GET:
$request = Request::create('/api/users/1', 'GET');
$response = Route::dispatch($request);
POST:
$request = Request::create('/api/users/1', 'POST', Input::get());
$response = Route::dispatch($request);
POST w/ cookies
$request = Request::create('/api/users/1', 'POST', Input::get(), Cookie::get('name'));
$response = Route::dispatch($request);
POST w/ files
$request = Request::create('/api/users/1', 'POST', Input::get(), null, Input::file('file'));
$response = Route::dispatch($request);
I hope this helps someone else. If you aren't using a form, or you are but not using Laravel's Input / Cookie facade, replace the Input / Cookie facades with your own content.
Taylor Otwell suggested using app()->handle() rather than Route::dispatch() to achieve a clean request.
For Route::dispatch($request) I noticed if the endpoint of your non-GET request (parameters on the HTTP request body) uses a dependency injected \Illuminate\Http\Request or \Illuminate\Foundation\Http\FormRequest extending instance, state of the parameters, cookies, files, etc. are from the original HTTP request. i.e., for your application's controller action method.
If parameter names and post method type for your app controller and API controller are the same, you won't notice the difference since the original parameter values are passed on. But when you're manually assembling the 3rd parameter of Request::create(), Route::dispatch() will result in it being ignored.
app()->handle() fixes that context problem in the Laravel request lifecycle.
Caveat: app()->handle() affects Illuminate\Support\Facades\Request, refreshing it with this new request instance. As a knock-on effect, calls like Request::isXmlHttpRequest() or redirect()->back() invoked after app()->handle() will cause unpredictable behaviour. I'd suggest tracking the context of your original request and instead use redirect()->to(route('...')) so you strictly control flow and state of your app.
Given all these corner cases, it may be best to just do a manual curl using a Guzzle HTTP client.
If you are looking for using passport login api internally, then you need to add the parameters to original request:
protected function manualLogin(Request $request)
{
$email = $request->input('email');
$password = $request->input('password');
$request->request->add([
'username' => $email,
'password' => $password,
'grant_type' => 'password',
'client_id' => $clientID,
'client_secret' => $clientSecret,
'scope' => '*']);
$newRequest = Request::create('/oauth/token', 'post');
return Route::dispatch($newRequest)->getContent();
}
If you're consuming your own API, use app()->handle() instead of Route::dispatch() as Derek MacDonald has suggested.
app()->handle() creates a fresh request, while Route::dispatch() runs the route within the stack, effectively ignoring parameters that are part of the request that you're sending.
Edit: Just a heads-up. Taylor Otwell advises against using sub-requests to make internal API calls, as they mess the current route. You can an HTTP API client like Guzzle instead to make the API calls.
You can use Optimus API consumer, the API is clean and simple, example making an internal request:
$response = app()->make('apiconsumer')->post('/oauth/token', $data);
In it's core, it uses Illuminate\Routing\Router and Illuminate\Http\Request to make the call
// create the request
$this->request->create($uri, $method, $data, [], [], $server, $content);
// get the response
$response = $this->router->prepareResponse($request, $this->app->handle($request));

Categories