Wrong body format when use Content-Type: application/json in default client

Issue #78 new
Paweł Balicki created an issue

If is specify Content-Type as apllication/json request body should be send as json, not http query.

Version: 1.1.2

Comments (3)

  1. Paweł Balicki reporter

    I've got a code where request is calling:

    <?php
    
    $bitbucket = new \Bitbucket\API\Api();
    $bitbucket->getClient()->addListener(new \Bitbucket\API\Http\Listener\OAuth2Listener($oauth_params));
    
    $reqHeaders = ['Content-Type' => 'application/json'];
    $reqParams = [
        'name'    => $forkName,
        'project' => [
            'key' => 'BP',
        ],
    ];
    $response = $bitbucket->getClient()->post(sprintf('repositories/%s/%s/forks', Config::$bitbucketUsername, 'project'), $reqParams, $reqHeaders);
    $response = json_decode($response->getContent(), true);
    

    In Bitbucket\API\Http\Client.php we can see request() method:

    <?php
    
    public function request($endpoint, $params = array(), $method = 'GET', array $headers = array())
    {
        //$request = $this->createRequest($method, $endpoint);
        $request = ($this->requestObj !== null) ? $this->requestObj : $this->createRequest($method, $endpoint);
    
        // add a default content-type if none was set
        if (empty($headers['Content-Type']) && in_array(strtoupper($method), array('POST', 'PUT'), true)) {
            $headers['Content-Type'] = 'application/x-www-form-urlencoded';
        }
    
        if (count($headers) > 0) {
            $request->addHeaders($headers);
        }
    
        $paramsString = null;
        if (is_array($params) && count($params) > 0) {
            $paramsString = http_build_query($params);
        }
    
        if (is_string($paramsString) && $paramsString !== null) {
            $request->setContent($paramsString);
        }
    
        if (is_string($params) && $params !== null) {
            $request->setContent($params);
        }
    
        $response = is_object($this->responseObj) ? $this->responseObj : new Response();
    
        $this->executeListeners($request, 'preSend');
    
        $this->client->send($request, $response);
    
        $this->executeListeners($request, 'postSend', $response);
    
        $this->lastRequest  = $request;
        $this->lastResponse = $response;
    
        return $response;
    }
    

    In my opinion this condition have missing Content-Type header check:

    <?php
    
    if (is_array($params) && count($params) > 0) {
        $paramsString = http_build_query($params);
    }
    
  2. Alexandru Guzinschi

    Ah, yes. That method's logic is a direct result of my mental reminiscence of BB API which at first didn't understood json at all, then only partial and some endpoints broke BC a few times.
    In a "fuck it" moment I made the decision to make no assumptions and move the "burden" of decision to the caller side.

    You can see this behaviour pretty much everywhere inside the library, for example where a content-type of application/json is used, the $params are sent as json encoded to the request method. example. This will cause the Client to set the string received in $params as request body

    Maybe after the death of BB API v1 at the end of this year and after we merge PR #41, we could change this and make a few sane defaults at least, so I will leave this issue open for now.

  3. Log in to comment