How do I configure default query parameters with Guzzle 6?
Asked Answered
K

4

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!

Kramlich answered 4/8, 2016 at 0:50 Comment(2)
See: github.com/guzzle/guzzle/issues/1138Smokedry
Good gravy. There should be a book: "Warning signals. When you're over engineering your library" Thanks man.Kramlich
K
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!

Kramlich answered 4/8, 2016 at 3:48 Comment(2)
I found a bit of a workaround for this, if you happen to still be interested see the answer I gave.Remise
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));Resistant
R
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.

Remise answered 18/11, 2019 at 10:4 Comment(7)
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)Dinsdale
@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.Remise
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 IMHODinsdale
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.Remise
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 :)Dinsdale
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 wayRemise
+1000 for DOCUMENTING $client->getConfig(param_passed_to_constructor); I couldnt find anywhere how the default configuration can be retrieved after client creationMontelongo
M
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

Meit answered 3/4, 2022 at 22:4 Comment(0)
I
-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();
Irrigation answered 6/11, 2018 at 15:10 Comment(2)
I found a bit of a workaround for this, if you happen to still be interested see the answer I gave.Remise
Why not use the query parts in the option array? The given code does not look good and does not use any escaping for parametersDinsdale

© 2022 - 2024 — McMap. All rights reserved.