239

Does anybody know the correct way to post JSON using Guzzle?

$request = $this->client->post(self::URL_REGISTER,array(
                'content-type' => 'application/json'
        ),array(json_encode($_POST)));

I get an internal server error response from the server. It works using Chrome Postman.

Hari Harker
  • 702
  • 1
  • 12
  • 29
user3379466
  • 3,087
  • 2
  • 14
  • 12
  • Request seems ok... have you checked the content of $_POST to be sure that you really get the values before encoding them ? : var_dump($_POST) – ylerjen Mar 07 '14 at 08:26
  • According to docs now, you can just use what @davykiash said, `'json' => $data`: https://stackoverflow.com/a/44154428/842768 – giovannipds Dec 11 '19 at 16:47

15 Answers15

343

For Guzzle 5, 6 and 7 you do it like this:

use GuzzleHttp\Client;

$client = new Client();

$response = $client->post('url', [
    GuzzleHttp\RequestOptions::JSON => ['foo' => 'bar'] // or 'json' => [...]
]);

Docs

Michal Gallovic
  • 4,109
  • 2
  • 18
  • 25
  • 14
    This is the right way to do ([official example here](http://docs.guzzlephp.org/en/latest/request-options.html#json)) – Pierre de LESPINAY Sep 10 '15 at 12:27
  • According to [doc](http://docs.guzzlephp.org/en/latest/quickstart.html#sending-requests) magic methods can be used. So `post()` should work. – robsch Jan 04 '17 at 15:44
  • 8
    It's recommended to use `RequestOptions` constants for the options array keys (`GuzzleHttp\RequestOptions::JSON` in this case) - it makes typos easier to detect as they suddenly become notices instead of just silent bugs waiting to cause trouble. – ksadowski Mar 22 '17 at 12:02
  • @ksadowski Can you share docs with this info ? In https://github.com/guzzle/guzzle/blob/master/src/RequestOptions.php#L140 RequestOptions::JSON is a constant with "json" - so it should be the same. – Michal Gallovic Mar 22 '17 at 17:38
  • 8
    @MichalGallovic It is the same. The purpose to use the constant is to avoid typos. Using a constant that does not exists will raise an error, but sending a useless option (as `jsson` for example) won't raise any error, and you may take some time to find your typo. – zessx Nov 02 '17 at 16:54
  • 1
    I was looking around for an hour for this answer. Why is this not in the documentation (especially the quick setup guide)? Crazy!?! – Robert Johnstone Mar 13 '19 at 12:03
  • According to docs now, you can just use what @davykiash said, `'json' => $data`: https://stackoverflow.com/a/44154428/842768 – giovannipds Dec 11 '19 at 16:46
  • 1
    @giovannipds GuzzleHttp\RequestOptions::JSON is an alias to 'json', either is fine. – Michal Gallovic Feb 08 '20 at 20:53
  • @Tebe tried with Guzzle ^6.3 and it works with json string as well as constant. – Michal Gallovic Feb 11 '20 at 08:54
  • just replaced library, much less hasssles , recommending this https://github.com/rmccue/Requests . what e mess it should be if sending simple post request take s a whole discussion – Tebe Feb 11 '20 at 10:11
  • When using a client supplied by Google APIs the `'json' => $data` syntax did not work for me. But the `GuzzleHTTP\RequestOptions::JSON` syntax worked as expected. – Peter Gluck Sep 19 '20 at 00:50
  • how would we handle actual list values in json , in this case – lazarus Dec 13 '22 at 09:26
62

The simple and basic way (guzzle6):

$client = new Client([
    'headers' => [ 'Content-Type' => 'application/json' ]
]);

$response = $client->post('http://api.com/CheckItOutNow',
    ['body' => json_encode(
        [
            'hello' => 'World'
        ]
    )]
);

To get the response status code and the content of the body I did this:

echo '<pre>' . var_export($response->getStatusCode(), true) . '</pre>';
echo '<pre>' . var_export($response->getBody()->getContents(), true) . '</pre>';
Frank Roth
  • 6,191
  • 3
  • 25
  • 33
55

For Guzzle <= 4:

It's a raw post request so putting the JSON in the body solved the problem

$request = $this->client->post(
    $url,
    [
        'content-type' => 'application/json'
    ],
);
$request->setBody($data); #set body!
$response = $request->send();
Valor_
  • 3,461
  • 9
  • 60
  • 109
user3379466
  • 3,087
  • 2
  • 14
  • 12
  • 11
    This no longer works with GuzzleHttp. @Charlie has the right answer – hbt Apr 22 '15 at 20:13
  • I think we just need to specify the version of Guzzle in the question. – Fabrice Kabongo Apr 05 '17 at 08:52
  • 3
    If you want to set the content type header in Guzzle 6, you can do it like this: `$client->post($url, ['body' => $string, 'headers' => ['Content-type' => 'application/json']]);` – marcovtwout Apr 13 '17 at 06:41
  • I have tried this with Guzzle3 is not working even if it is the way mentionned in the doc : https://guzzle3.readthedocs.io/http-client/request.html?highlight=raw#raw-post-data , it's been 2 days I am trying to solve this pb but in vain – Hanane Sep 30 '19 at 14:42
  • According to docs now, you can just use what @davykiash said, `'json' => $data`: https://stackoverflow.com/a/44154428/842768 – giovannipds Dec 11 '19 at 16:47
38

This worked for me (using Guzzle 6)

$client = new Client(); 
$result = $client->post('http://api.example.com', [
            'json' => [
                'value_1' => 'number1',
                'Value_group' =>  
                             array("value_2" => "number2",
                                    "value_3" => "number3")
                    ]
                ]);

echo($result->getBody()->getContents());
davykiash
  • 1,796
  • 5
  • 27
  • 60
25
$client = new \GuzzleHttp\Client();

$body['grant_type'] = "client_credentials";
$body['client_id'] = $this->client_id;
$body['client_secret'] = $this->client_secret;

$res = $client->post($url, [ 'body' => json_encode($body) ]);

$code = $res->getStatusCode();
$result = $res->json();
CharlieJade
  • 1,173
  • 14
  • 10
  • 2
    Does this also set the correct header? I think `['json' => $body]` is the better way here, as mentioned by Michael's answer. – Ja͢ck Jun 16 '15 at 08:54
  • 1
    `$res->json();` only works in Guzzle 5.3. It's been removed in v6. – David Mar 29 '16 at 15:41
  • 1
    David is correct. This is because of PSR-7 implementation. Use `json_decode()` instead. – Andreas May 16 '16 at 08:40
  • this will not work when you have to send headers, f.e. authorization tokens for git. you have to instantiate a Request object and use the send or request function – clockw0rk Aug 17 '20 at 12:42
22

You can either using hardcoded json attribute as key, or you can conveniently using GuzzleHttp\RequestOptions::JSON constant.

Here is the example of using hardcoded json string.

use GuzzleHttp\Client;

$client = new Client();

$response = $client->post('url', [
    'json' => ['foo' => 'bar']
]);

See Docs.

Nurul Huda
  • 1,438
  • 14
  • 12
11
$client = new \GuzzleHttp\Client(['base_uri' => 'http://example.com/api']);

$response = $client->post('/save', [
    'json' => [
        'name' => 'John Doe'
    ]
]);

return $response->getBody();
Yamen Ashraf
  • 2,637
  • 2
  • 20
  • 26
8

This works for me with Guzzle 6.2 :

$gClient =  new \GuzzleHttp\Client(['base_uri' => 'www.foo.bar']);
$res = $gClient->post('ws/endpoint',
                            array(
                                'headers'=>array('Content-Type'=>'application/json'),
                                'json'=>array('someData'=>'xxxxx','moreData'=>'zzzzzzz')
                                )
                    );

According to the documentation guzzle do the json_encode

arcos.lwm
  • 101
  • 1
  • 5
5

Solution for $client->request('POST',...

For those who are using $client->request this is how you create a JSON request:

$client = new Client();
$res = $client->request('POST', "https://some-url.com/api", [
    'json' => [
        'paramaterName' => "parameterValue",
        'paramaterName2' => "parameterValue2",
    ]
    'headers' => [
    'Content-Type' => 'application/json',
    ]
]);

Guzzle JSON Request Reference

Stas Sorokin
  • 3,029
  • 26
  • 18
2

Php Version: 5.6

Symfony version: 2.3

Guzzle: 5.0

I had an experience recently about sending json with Guzzle. I use Symfony 2.3 so my guzzle version can be a little older.

I will also show how to use debug mode and you can see the request before sending it,

When i made the request as shown below got the successfull response;

use GuzzleHttp\Client;

$headers = [
        'Authorization' => 'Bearer ' . $token,        
        'Accept'        => 'application/json',
        "Content-Type"  => "application/json"
    ];        

    $body = json_encode($requestBody);

    $client = new Client();    

    $client->setDefaultOption('headers', $headers);
    $client->setDefaultOption('verify', false);
    $client->setDefaultOption('debug', true);

    $response = $client->post($endPoint, array('body'=> $body));

    dump($response->getBody()->getContents());
Tuncay Elvanagac
  • 1,048
  • 11
  • 13
0

@user3379466 is correct, but here I rewrite in full:

-package that you need:

 "require": {
    "php"  : ">=5.3.9",
    "guzzlehttp/guzzle": "^3.8"
},

-php code (Digest is a type so pick different type if you need to, i have to include api server for authentication in this paragraph, some does not need to authenticate. If you use json you will need to replace any text 'xml' with 'json' and the data below should be a json string too):

$client = new Client('https://api.yourbaseapiserver.com/incidents.xml', array('version' => 'v1.3', 'request.options' => array('headers' => array('Accept' => 'application/vnd.yourbaseapiserver.v1.1+xml', 'Content-Type' => 'text/xml'), 'auth' => array('username@gmail.com', 'password', 'Digest'),)));

$url          = "https://api.yourbaseapiserver.com/incidents.xml";
        
$data = '<incident>
<name>Incident Title2a</name>
<priority>Medium</priority>
<requester><email>dsss@mail.ca</email></requester>
<description>description2a</description>
</incident>';
    $request = $client->post($url, array('content-type' => 'application/xml',));

    $request->setBody($data); #set body! this is body of request object and not a body field in the header section so don't be confused.

    $response = $request->send(); #you must do send() method!
    echo $response->getBody(); #you should see the response body from the server on success
    die;

--- Solution for * Guzzle 6 * --- -package that you need:

 "require": {
    "php"  : ">=5.5.0",
    "guzzlehttp/guzzle": "~6.0"
},

$client = new Client([
                             // Base URI is used with relative requests
                             'base_uri' => 'https://api.compay.com/',
                             // You can set any number of default request options.
                             'timeout'  => 3.0,
                             'auth'     => array('you@gmail.ca', 'dsfddfdfpassword', 'Digest'),
                             'headers' => array('Accept'        => 'application/vnd.comay.v1.1+xml',
                                                'Content-Type'  => 'text/xml'),
                         ]);

$url = "https://api.compay.com/cases.xml";
    $data string variable is defined same as above.


    // Provide the body as a string.
    $r = $client->request('POST', $url, [
        'body' => $data
    ]);

    echo $r->getBody();
    die;
Dung
  • 19,199
  • 9
  • 59
  • 54
  • Thank you. Could not find any guzzle3 solution anywhere else for legacy php5.3 projects, would like to see it line-break'd like your guzzle6 aswell since it would have saved me alot of time. – taur Jul 10 '20 at 08:00
0

Simply use this it will work

   $auth = base64_encode('user:'.config('mailchimp.api_key'));
    //API URL
    $urll = "https://".config('mailchimp.data_center').".api.mailchimp.com/3.0/batches";
    //API authentication Header
    $headers = array(
        'Accept'     => 'application/json',
        'Authorization' => 'Basic '.$auth
    );
    $client = new Client();
    $req_Memeber = new Request('POST', $urll, $headers, $userlist);
    // promise
    $promise = $client->sendAsync($req_Memeber)->then(function ($res){
            echo "Synched";
        });
      $promise->wait();
0

I use the following code that works very reliably.

The JSON data is passed in the parameter $request, and the specific request type passed in the variable $searchType.

The code includes a trap to detect and report an unsuccessful or invalid call which will then return false.

If the call is sucessful then json_decode ($result->getBody(), $return=true) returns an array of the results.

    public function callAPI($request, $searchType) {
    $guzzleClient = new GuzzleHttp\Client(["base_uri" => "https://example.com"]);

    try {
        $result = $guzzleClient->post( $searchType, ["json" => $request]);
    } catch (Exception $e) {
        $error = $e->getMessage();
        $error .= '<pre>'.print_r($request, $return=true).'</pre>';
        $error .= 'No returnable data';
        Event::logError(__LINE__, __FILE__, $error);
        return false;
    }
    return json_decode($result->getBody(), $return=true);
}
Mike M0ITI
  • 31
  • 1
  • 5
-1

The answer from @user3379466 can be made to work by setting $data as follows:

$data = "{'some_key' : 'some_value'}";

What our project needed was to insert a variable into an array inside the json string, which I did as follows (in case this helps anyone):

$data = "{\"collection\" : [$existing_variable]}";

So with $existing_variable being, say, 90210, you get:

echo $data;
//{"collection" : [90210]}

Also worth noting is that you might want to also set the 'Accept' => 'application/json' as well in case the endpoint you're hitting cares about that kind of thing.

halfer
  • 19,824
  • 17
  • 99
  • 186
j boschiero
  • 480
  • 1
  • 3
  • 13
  • Just a heads up... you can simplify your `$data` by using `json_encode`: `$data = json_encode(array('collection' => $existing_variable));` – phpisuber01 Oct 30 '14 at 20:33
-1

Above answers did not worked for me somehow. But this works fine for me.

 $client = new Client('' . $appUrl['scheme'] . '://' . $appUrl['host'] . '' . $appUrl['path']);

 $request = $client->post($base_url, array('content-type' => 'application/json'), json_encode($appUrl['query']));
Suraj
  • 2,181
  • 2
  • 17
  • 25