Forcing a Content-Type header with Guzzle's form_params

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

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.