Forcing a Content-Type header with Guzzle's form_params

Tired of the privacy invasion of the Chrome webbrowser? Worried about the risk of seeing ads everywhere? Give the Brave Browser a try. It supports all the same Chrome extensions, with none of the telemetry. It auto-blocks ads and helps support content creators like me.

Give the Brave browser a try »

Profile image of Mattias Geniar

Mattias Geniar, March 09, 2020

Follow me on Twitter as @mattiasgeniar

I just lost an hour or 2 of my life to this, so I figure I’ll do a small write-up to save future me from having to do the same dance.

I had the following piece of code, that wasn’t doing what I expected.

<?php
$client = new Client([
    'http_errors' => false,
    'verify' => false,
    'headers' => [
        'Content-Type' => 'application/json',
    ],
]);

try {
    $response = $client->post('/', [
        'form_params' => '{"query":"{some_json}"}',
    ]);
} catch (GuzzleException $exception) {
    // ...
}

Whenever the Guzzle call would execute, it would overwrite my provided Content-Type header with the application/x-www-form-urlencoded value.

What I’m trying to do looks weird, but is intentional: I want to send a JSON payload, but send it as if it was a simple form submission. I don’t want to use Guzzle’s json method for this.

This should work, because the docs say:

[form_params] Sets the Content-Type header to application/x-www-form-urlencoded when no Content-Type header is already present.

But my header was already present, yet Guzzle overwrites it!

Turns out, I was applying that header in the wrong place. Silly me. The headers array should be moved directly to the $client->post() call, not set as the defaults of the client.

My fix was to just move them:

<?php
$client = new Client([
    'http_errors' => false,
    'verify' => false,
]);

try {
    $response = $client->post('/', [
        'headers' => [
            'Content-Type' => 'application/json',
        ],
        'form_params' => '{"query":"{some_json}"}',
    ]);
} catch (GuzzleException $exception) {
    // ...
}

Remove them from the Client() instantiation and set the headers directly to the HTTP call that is being executed.

Lesson learned: the docs might be right, but they aren’t very clear.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.