TomJ
TomJ

Reputation: 310

cURL POST request works, Guzzle 6 does not

Context:

I've been working on figuring out how to make this work for a while, and I simply don't understand why Guzzle isn't working for this particular request. The same initialization and request structure works in some basic unit tests I have, but when it comes to API to API communication, Guzzle just is not cooperating.

Problem:

What I mean by that is, it's not including the headers I'm setting in the $headers array, and the request body is empty.

Desired result:

To confirm this is an issue with Guzzle, I've written out the request with typical cURL syntax, and the request goes through fine. I just need some guidance on how to make this work with Guzzle, as I like the abstraction Guzzle offers over verbose cURL requests.

Working cURL request:

    $headers = array(
        'Authorization: Bearer '.$sharedSecret,
        'Content-Type: application/x-www-form-urlencoded',
        'Accept: application/json',
        'Content-Length: '.strlen($loginDetails),
    );

    $curlOptions = array(
        CURLOPT_URL             => API_URL.'member/SessionManager',
        CURLOPT_HTTPHEADER      => $headers,
        CURLOPT_RETURNTRANSFER  => FALSE,
        CURLOPT_HEADER          => FALSE,
        CURLOPT_FOLLOWLOCATION  => FALSE,
        CURLOPT_ENCODING        => "",
        CURLOPT_USERAGENT       => "PORTAL",
        CURLOPT_AUTOREFERER     => TRUE,
        CURLOPT_CONNECTTIMEOUT  => 120,
        CURLOPT_TIMEOUT         => 120,
        CURLOPT_MAXREDIRS       => 10,
        CURLOPT_POST            => TRUE,
        CURLOPT_POSTFIELDS      => $loginDetails,
        CURLOPT_SSL_VERIFYHOST  => FALSE,
        CURLOPT_SSL_VERIFYPEER  => FALSE,
        CURLOPT_VERBOSE         => FALSE
    );

    try {
        $ch = curl_init();
        curl_setopt_array($ch,$curlOptions);
        $content    = curl_exec($ch);
        $err        = curl_errno($ch);
        $errmsg     = curl_error($ch);
        $response   = curl_getinfo($ch);
        curl_close($ch);

        if ($content === FALSE) {
            throw new Exception(curl_error($ch), curl_errno($ch));
        } else {
            return true;
        }
    } catch(Exception $e) {
        trigger_error(sprintf('Curl failed with error #%d: %s', $e->getCode(), $e->getMessage()), E_USER_ERROR);
    }

The Guzzle client is initialized in a global file that creates a container which stores various objects we use throughout the application. I'm including it in case I missed something vital that isn't in Guzzle's documentation.

Guzzle initialization:

$container['client'] = function ($c) {
    return new \GuzzleHttp\Client([
        'base_uri'          => API_URL,
        'timeout'           => 30.0,
        'allow_redirects'   => true,
        'verify'            => false,
        'verbose'           => true,
        [
            'headers'   => [
                'Authorization' => 'Bearer '.$sharedSecret,
            ]
        ],
    ]);
};

Non-working Guzzle Request:

    $headers = array(
        'Authorization' => 'Bearer '.$sharedSecret,
        'Content-Type'  => 'application/x-www-form-urlencoded',
        'Accept'        => 'application/json',
        'Content-Length'=> strlen($loginDetails),
    );

    try {
        $response = $this->client->post('/api/member/SessionManager',
            ['debug'            => true],
            ['headers'          => $headers],
            ['body'             => $loginDetails]
        );

        if($response) {
            $this->handleResponse($response);
        }

    } catch (GuzzleHttp\Exception\ClientException $e) {
        $response->getResponse();
        $responseBodyAsString = $response->getBody()->getContents();
    }

Whether I remove the headers array in the Guzzle initialization or not, it doesn't matter. The Authorization header is nowhere to be found in the request (confirmed with tcpdump, Wireshark, and receiving API error logging), and Guzzle's debug output shows no indication of my headers, nor my request body being anywhere in the request.

I'm stumped as to why this isn't working, and would very much like to understand. I can go the route of not using Guzzle, but would really prefer to due to brevity. Any input would be greatly appreciated.

Upvotes: 2

Views: 1532

Answers (2)

dearsina
dearsina

Reputation: 5167

Appreciate that the question is old, but I thought I'd share my experience as I also struggled with this. The equivalent of:

CURLOPT_POSTFIELDS      => $loginDetails,

in Guzzle is:

"query" => $loginDetails

In addition, I have found that if the base_uri does not end with a /, Guzzle will misunderstand it.

With all that in mind, your POST request should be as follows:

        $response = $this->client->post('api/member/SessionManager', // Removed the first / as it's part of the base_uri now
            ['debug'            => true],
            ['headers'          => $headers],
            ['query'            => $loginDetails] // Replaced "body" with "query"
        );

Upvotes: 0

ViralP
ViralP

Reputation: 233

In cURL request, the API URL being called is

API_URL.'member/SessionManager'

While in Guzzle request, the API URL being called has extra text "/api/" (assuming API_URL is defined same in both cases)

new \GuzzleHttp\Client([ 'base_uri' => API_URL,

...

$this->client->post('/api/member/SessionManager',

Upvotes: 4

Related Questions