6

Migrating from 5 to 6, and I've run into a snag and can't find the relevant docs.

Guzzle docs here, http://guzzle.readthedocs.io/en/latest/quickstart.html#creating-a-client, site that we can add "any number of default request options".

I want to send "foo=bar" with every request. E.g.:

$client = new Client([
    'base_uri' => 'http://google.com',
]);

$client->get('this/that.json', [
    'query' => [ 'a' => 'b' ],
]);

This will generate GET on http://google.com/this/that.json?a=b

How do I modify the client construction so that it yields:

http://google.com/this/that.json?foo=bar&a=b

Thanks for your help!

Saeven
  • 2,280
  • 1
  • 20
  • 33

4 Answers4

8

Alright, so far, this works here:

        $extraParams = [
            'a' => $config['a'],
            'b' => $config['b'],
        ];

        $handler = HandlerStack::create();
        $handler->push(Middleware::mapRequest(function (RequestInterface $request) use ($extraParams) {

            $uri  = $request->getUri();
            $uri .= ( $uri ? '&' : '' );
            $uri .= http_build_query( $extraParams );

            return new Request(
                $request->getMethod(),
                $uri,
                $request->getHeaders(),
                $request->getBody(),
                $request->getProtocolVersion()
            );
        }));

        $this->client = new Client([
            'base_uri' => $url,
            'handler' => $handler,
            'exceptions' => false,
        ]);

If anyone knows how to make it less sinister-looking, I would say thank you!

Saeven
  • 2,280
  • 1
  • 20
  • 33
  • I found a bit of a workaround for this, if you happen to still be interested see the answer I gave. – DazBaldwin Nov 18 '19 at 10:08
  • 1
    An other way modify query $queryString = $request->getUri()->getQuery(); $queryParts = \GuzzleHttp\Psr7\parse_query($queryString); $queryParts[$this->name] = $this->value; $queryString = \GuzzleHttp\Psr7\build_query($queryParts); return $request->withUri($request->getUri()->withQuery($queryString)); – Vladimir Pak Oct 13 '20 at 08:55
5

I found a nice solution here.

Basically, anything defined in the first array of arguments, become part of the config for the client.

this means you can do this when initialising:

$client = new Client([
    'base_uri' => 'http://google.com',
    // can be called anything but defaults works well
    'defaults' => [
        'query'  => [
            'foo' => 'bar',
        ]
    ]
]);

Then, when using the client:

$options = [
    'query'  => [
        'nonDefault' => 'baz',
    ]
];

// merge non default options with default ones
$options = array_merge_recursive($options, $client->getConfig('defaults'));

$guzzleResponse = $client->get('this/that.json', $options);

It's woth noting that the array_merge_recursive function appends to nested arrays rather than overwrites. If you plan on changing a default value, you'll need a different utility function. It works nicely when the default values are immutable though.

DazBaldwin
  • 4,125
  • 3
  • 39
  • 43
  • This does not really look good. Using a middleway approach, like given by Saeven, you have to configure all this stuff **once** (in the middleware) and not before each request (as in your code) – Nico Haase Nov 18 '19 at 10:10
  • @NicoHaase, I mean, the defaults only get set once. The additional **one line** is a lot more readable and declarative than messing with `HandlerStack`, `Middleware`, `RequestInterface`, and `Request` Objects and functions IMO. – DazBaldwin Nov 18 '19 at 10:15
  • 2
    But if you are using multiple Guzzle requests at different parts in your application, you have to remember to put that one extra line at each and every call. Configuring it using the middleware abstracts this better IMHO – Nico Haase Nov 18 '19 at 10:20
  • 1
    Thanks @NicoHaase, That is a valid point. I actually create static classes to access my clients through, so this functionality happens implicitly rather than explicitly anyway and I don't even need the extra one line per request (I just extracted the code to make it more apparent what was happening). I think you would need to do something similar with the answer provided by Seaven anyway. They also asked for a less sinister looking solution, which I think this is. – DazBaldwin Nov 18 '19 at 10:29
  • Using Seavens answer, you could create a `ClientFactory` which returns a client perfectly configured (containing the proper middleware) - so you just had to write this code once there. And I didn't want to say that your solution is bad, but I'd prefer the middleware approach. Thanks for a good discussion, Daz :) – Nico Haase Nov 18 '19 at 14:38
  • 2
    Same @NicoHaase, I'm sort of doing just that with my static classes (not strictly a factory pattern but very similar), I always do so with Guzzle clients. Personally, I've always felt that the guzzle middleware documentation is somewhat lacking for such a massive feature. The thing is, when I stumbled across this question, all I wanted to do was add `key=val` to the URL for all requests made from one particular guzzle client. I didn't feel that justified spending the time looking through the various sources of docs. Anything more complex though and Saeven's solution would definitely be the way – DazBaldwin Nov 19 '19 at 09:33
  • 1
    +1000 for DOCUMENTING $client->getConfig(param_passed_to_constructor); I couldnt find anywhere how the default configuration can be retrieved after client creation – cnlevy Jul 20 '21 at 09:01
2

A "less sinister-looking" example based on the answer by @Saeven and the comment from @VladimirPak.

        $query_defaults = [
            'a' => $config['a'],
            'b' => $config['b'],
        ];

        $handler = \GuzzleHttp\HandlerStack::create();
        $handler->push(\GuzzleHttp\Middleware::mapRequest(function (\Psr\Http\Message\RequestInterface $request) use ($query_defaults) {

            $query = \GuzzleHttp\Psr7\Query::parse($request->getUri()->getQuery());
            $query = array_merge($query_defaults, $query);

            return $request->withUri($request->getUri()->withQuery(\GuzzleHttp\Psr7\Query::build($query)));

        }));

        $this->client = new \GuzzleHttp\Client([
            'base_uri' => $url,
            'handler' => $handler,
            'exceptions' => false,
        ]);

I'm not sure how less sinister-looking it is though. lol

Ryan Worth
  • 151
  • 2
  • 9
-3

the solution proposed in github looks pretty ugly. This does not look much better, but at least is more readable and also works. I'd like feedback if anyone knows why should not be used:

$query = $uri . '/person/id?personid=' . $personid . '&name=' . $name;    
return $result = $this->client->get(
  $query
  )
  ->getBody()->getContents();
Alejandro Moreno
  • 5,578
  • 2
  • 31
  • 29
  • 1
    I found a bit of a workaround for this, if you happen to still be interested see the answer I gave. – DazBaldwin Nov 18 '19 at 10:08
  • Why not use the `query` parts in the option array? The given code does not look good and does not use any escaping for parameters – Nico Haase Nov 18 '19 at 10:09