4

I am making the following request using Zend\Http\Request and Zend\Http\Client

        //Creating request and client objects
        $request = new Request();
        $client = new Client();

        //Preparing Request Object
        $request->setMethod('POST');
        $request->setUri('https://my.api.address.com/apiendpointurl1234');
        $request->getHeaders()->addHeaders(array(
            'cache-control' => 'no-cache',
            'content-type' => 'application/json',
            'client_secret' => 'asdfasdfasdfasdfasdf',
            'client_id' => 'asdfasdfasdfasdfasdf',
            'accept' => 'application/json',
            'authorization' => 'Basic MTIzNDoxMjM0',
        ));
        $request->getPost()->set(json_encode(array(
            'student_id' => '123456',
            'short_description' => 'this is short description',
            'description' => 'this is detailed description of the question',
        )));

        //Sending Request
        $response = $client->send($request);

        var_dump( $response->getBody() );

However the response comes with this error:

"error": "headers: client_id required"

When I poke the API via Postman, it works fine. But when I call it from the PHP application, it turns out that the headers are not being sent correctly, which is giving the above error. Anyone would know why the headers aren't being sent?

HelmBurger
  • 1,168
  • 5
  • 15
  • 35

6 Answers6

2

try without addHeaders method

// Setting multiple headers, overwriting any previous value
$client->setHeaders(array(
    'Host' => 'www.example.com',
    'Accept-encoding' => 'gzip,deflate',
    'X-Powered-By' => 'Zend Framework'));

and maybe you have some confuse with client and request objects.

   $client = new Zend_Http_Client('http://example.org');
      $client->setHeaders(array(
        'Host' => 'www.example.com',
        'Accept-encoding' => 'gzip,deflate',
        'X-Powered-By' => 'Zend Framework'));
    $response = $client->request();

and you can inspect your query in firebug for example and check what headers are sent in server

bxN5
  • 1,430
  • 2
  • 16
  • 27
  • setHeaders requires Header type headers. Did that. No success. Firebug shows what Chrome inspector shows already – HelmBurger Jan 20 '17 at 05:59
1

If you want to use Request object, you have use setRequest and dispatch methods:

use Zend\Http\Client;
use Zend\Http\Request;

$request = new Request();
$request->setUri('https://my.api.address.com/apiendpointurl1234');

// Performing a POST request
$request->setMethod(Request::METHOD_POST);
$request->getHeaders()->addHeaders(array(
        'cache-control' => 'no-cache',
        'content-type' => 'application/json',
        'client_secret' => 'asdfasdfasdfasdfasdf',
        'client_id' => 'asdfasdfasdfasdfasdf',
        'accept' => 'application/json',
        'authorization' => 'Basic MTIzNDoxMjM0',
    ));

$client = new Client();

$client->setRequest($request);
$response = $client->dispatch();
Gennadiy Litvinyuk
  • 1,536
  • 12
  • 21
1

Here is what worked for me:

//Creating request and client objects
$request = new Request();
$client = new Client();

//Preparing Request Object
$request->setMethod('POST');
$request->setUri('https://my.api.address.com/apiendpointurl1234');
$request->getHeaders()->addHeaders(array(
    'cache-control' => 'no-cache',
    'content-type' => 'application/json',
    'client_secret' => 'asdfasdfasdfasdfasdf',
    'client_id' => 'asdfasdfasdfasdfasdf',
    'accept' => 'application/json',
    'authorization' => 'Basic MTIzNDoxMjM0'
));

$client->setOptions(['strictredirects' => true]);

$request->setContent(json_encode(array(
    'student_id' => '123456',
    'short_description' => 'this is short description',
    'description' => 'this is detailed description of the question',
)));

//Sending Request
$response = $client->send($request);

echo ($response->getBody());

My assumption is that there is a redirect from your api to another url and the headers get reset. You can see that at line 943 of Client.php where

$this->resetParameters(false, false);

is called. This does not happen in Postman since Postman reuses the same headers for the redirect.

Actually, you can test this by adding just adding

$client->setOptions(['strictredirects' => true]);

which should allow headers to be kept between redirects.

PS: I tried the code above with the latest stable version of zend http and it throw me some errors at the "$request->getPost()->set" line. Anyway, this is not the source of the issue.

EDIT: My 2nd assumption is that "client_id" header name is queried case-sensitive by the api, which causes the error, because the request is sent by Zend\Http\Client, it uses "Zend\Http\Client\Adapter\Socket" which makes the first character of each header uppercase(line 361). So "Client_id" is actual sent. Edit line 361 of Zend\Http\Client\Adapter\Socket":

 $v = ucfirst($k) . ": $v";

to

  $v = $k . ": $v";

and test if the header is received.

Jannes Botis
  • 11,154
  • 3
  • 21
  • 39
  • Hi Jannes! I tried inserting `strictredirects` but still had no success. My API might be going to another API where it's losing the headers but setting `strictredirects` to `true` doesn't seem to fix the problem. – HelmBurger Jan 25 '17 at 05:15
  • Don't know if that helps, but it seems that headers are actually being sent as making changes to `content-type` and `content-length` header affects the output. Don't know why `client_id` is not being transmitted. – HelmBurger Jan 25 '17 at 05:26
  • When the request is sent by Zend\Http\Client, it uses "Zend\Http\Client\Adapter\Socket" which makes the first character of each header uppercase(line 361), you can check if this the problem by changing that line – Jannes Botis Jan 25 '17 at 09:32
  • Removed the `ucfirst`, still no luck. – HelmBurger Jan 29 '17 at 01:50
  • Can you post the version of zend http you are using? – Jannes Botis Jan 29 '17 at 17:43
1

I bet you'd need to store the reference to Headers object in a variable right after you getHeaders, manipulate that object, and then use setHeaders to update headers on a Request object.

$headers = $request->getHeaders();
$headers->addHeaders([ ... ... ]);
$request->setHeaders($headers);
Mister Spock
  • 201
  • 1
  • 6
  • Hi Mister Spock! I know that does make difference in some scnarios but in my scenario, it doesn't affect the output in any way – HelmBurger Jan 25 '17 at 05:24
1

If i remember correctly it's been a while since i used Zend Framework for Requests but the getHeaders method returns the Headers object so you need to use and set.

So your code

 $request->getHeaders()->addHeaders(array(
     'cache-control' => 'no-cache',
     'content-type' => 'application/json',
     'client_secret' => 'asdfasdfasdfasdfasdf',
     'client_id' => 'asdfasdfasdfasdfasdf',
     'accept' => 'application/json',
     'authorization' => 'Basic MTIzNDoxMjM0',
));

Will need to become

 $headers = $request->getHeaders();
 $headers->addHeaders(array(
     'cache-control' => 'no-cache',
     'content-type' => 'application/json',
     'client_secret' => 'asdfasdfasdfasdfasdf',
     'client_id' => 'asdfasdfasdfasdfasdf',
     'accept' => 'application/json',
     'authorization' => 'Basic MTIzNDoxMjM0',
 ));
 $request->setHeaders($headers);

As said in one of the others Answers:

you will need to set the URI and method as Post before you do this as you will need the other headers

$request->setUri('https://my.api.address.com/apiendpointurl1234');

// Performing a POST request
$request->setMethod(Request::METHOD_POST);

And Lastly you will need to set your post data before you do this as it will affect your headers as Content-Length header needs to be set before you start messing with them

$request->setContent(json_encode(array(
    'student_id' => '123456',
    'short_description' => 'this is short description',
    'description' => 'this is detailed description of the question',
)));

So all together you script should be

//Creating request and client objects
$request = new Request();
$client = new Client();
$request->setUri('https://my.api.address.com/apiendpointurl1234');

// Performing a POST request
$request->setMethod(Request::METHOD_POST);
$client->setOptions(['strictredirects' => true]);

$request->setContent(json_encode(array(
    'student_id' => '123456',
    'short_description' => 'this is short description',
    'description' => 'this is detailed description of the question',
)));
$headers = $request->getHeaders();
$headers->addHeaders(array(
    'cache-control' => 'no-cache',
    'content-type' => 'application/json',
    'client_secret' => 'asdfasdfasdfasdfasdf',
    'client_id' => 'asdfasdfasdfasdfasdf',
    'accept' => 'application/json',
    'authorization' => 'Basic MTIzNDoxMjM0',
));
$request->setHeaders($headers);
Barkermn01
  • 6,781
  • 33
  • 83
  • Did all of what you mentioned, but no help. I'll definitely post my answer whatever solves the problem. Thanks – HelmBurger Jan 29 '17 at 01:57
  • Can we please see the output from `$request->toString();` method after all of this to see what Zend Frameworks `\Http\Request` is building – Barkermn01 Jan 29 '17 at 12:17
  • Turns out that your way of debugging helped me found the problem. So Zend is converting `client_id` to `client-id`, but call is still not being made. I'll post my solution soon. Thanks a lot – HelmBurger Jan 30 '17 at 02:50
0

Turns out that Zend\Http\Request and Zend\Http\Client libraries converts underscores to hyphen (-) at the time of making the call. However, cURL behaves a bit differently. Still if you supply headers array in key value format, you won't be able to make the call as cURL will convert client-id to client-id. However, if you supply an standard array of values only by concatenating the headers, the call is successful. So here is my replacement code that worked:

    // Get cURL resource
    $curl = curl_init();
    // Set some options - we are passing in a useragent too here
    curl_setopt_array($curl, [
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_URL => 'https://my.api.address.com/apiendpointurl1234',
        CURLOPT_POST => 1,
        CURLOPT_HTTPHEADER => [
            'client_id: ' . 'asdfasdfasdfasdf',
            'client_secret: ' . 'asdfasdfasdfasdfasdf',
            'Authorization: ' . 'Basic MTIzNDoxMjM0',
            'Content-Type: ' . 'application/json',
        ],
        CURLOPT_POSTFIELDS => [
            'student_id' => '111',
            'short_description' => 'this is the short description',
            'description' => 'this is the long description this is the long description this is the long description'
        ],
    ]);
    // Send the request & save response to $resp
    $response = curl_exec($curl);
    var_dump("Service call id is: " . $response);
    // Close request to clear up some resources
    curl_close($curl);

Hope that helps.

HelmBurger
  • 1,168
  • 5
  • 15
  • 35