Guzzle: URI parameters cannot repeat

Created on 12 Nov 2015  路  5Comments  路  Source: guzzle/guzzle

Hi.

I am accessing the Echo Nest API, which requires me to repeat the same uri parameter name. However I can't make this work in Guzzle 6. I read a similar issue from 2012, however the approach does not work.

I have tried adding it manually into the query string without any success.

A sample API call could be:

http://developer.echonest.com/api/v4/song/search?format=json&results=10&api_key=someKey&artist=Silbermond&title=Ja&bucket=id:spotify&bucket=tracks&bucket=audio_summary

I can't find any way to do this, so I'm raising it here as an issue now:

Here's my example Client:

    /**
     * @param array $urlParameters
     * @return Client
     */
    protected function getClient()
    {
        return new Client([
            'base_uri' => 'http://developer.echonest.com/api/v4/',
            'timeout'  => 5.0,
            'headers' => [
                'Accept' => 'application/json',
            ],
            'query' => [
                'api_key' => 'someKey',
                'format' => 'json',
                'results' => '10',
                'bucket' => 'id:spotify'         // I need multiple bucket parameter values with the 'bucket'-name
        ]);
    }

    /**
     * @param $artist
     * @param $title
     * @return stdClass|null
     */
    public function searchForArtistAndTitle($artist, $title)
    {
        $response = $this->getClient()->->get(
            'song/search',
            [
                'query' => array_merge($client->getConfig('query'), [
                    'artist' => $artist,
                    'title' => $title
                ])
            ]
        );

        // ...
    }

Thanks.

Most helpful comment

Just for the record if anyone else needs it, this way of stating uri parameters with the same name works:

$client = new Client([
    'base_uri' => 'http://developer.echonest.com/api/v4/',
    'timeout'  => 5.0,
    'headers' => [
        'Accept' => 'application/json',
    ]
]);

$response = $client->get(
    'song/search',
    [
        'query' => 'bucket=something&bucket=somethingElse'
    ]
);

All 5 comments

Due to the repeating keys, you'll need to provide the query request option as a string. I can't think of a great way to make this any easier (even with a query class to abstract this), considering you need to merge in options to the default query parameters.

Closing as a duplicate of https://github.com/guzzle/guzzle/issues/1196. Feel free to +1 that issue and provide feedback on what you think the best path forward is.

And you just fixed my problem. Thanks.
Stating a string as the query allows me to have repeating url parameters.

Just for the record if anyone else needs it, this way of stating uri parameters with the same name works:

$client = new Client([
    'base_uri' => 'http://developer.echonest.com/api/v4/',
    'timeout'  => 5.0,
    'headers' => [
        'Accept' => 'application/json',
    ]
]);

$response = $client->get(
    'song/search',
    [
        'query' => 'bucket=something&bucket=somethingElse'
    ]
);

I have been struggling with this issue and thank you to @skovmand for highlighting that if you use query as a string you can put duplicate parameter keys in.

I thought I'd share a custom function that does this for me, whilst still giving the user of my API wrapper the ability to use Arrays.

/**
     * 
     * @param array $firstArray
     * @param array $mergeFrom
     *
     * @return string
     */
    private function convertArrayMergeToQueryString(array $firstArray, array $mergeFrom): string
    {
        $str = '';
        foreach ($firstArray as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $subvalue) {
                    $str .= $key.'='.$subvalue.'&';
                }
            } else {
                $str .= $key . '=' . $value . '&';
            }
        }
        foreach ($mergeFrom as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $subvalue) {
                    $str .= $key.'='.$subvalue.'&';
                }
            } else {
                $str .= $key . '=' . $value . '&';
            }
        }
        return $str;
    }

It's not exactly the same as array_merge as it won't strip out duplicates at all, but in my case (and for most API) they will take the last attribute in the string if duplicates are not allowed.

Was this page helpful?
0 / 5 - 0 ratings