Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

brianh's avatar

testing JSON api with json() and Request::capture()->json()

I have a JSON API and the api.php route file uses Request::capture()->json(); to get the json body of the request. When I make a request in Postman it works, but when I try to write a test using the $this->json() function, the Request::capture()->json() is empty.

From the route file:

Route::group(['prefix' => 'v0', 'middleware' => [V0Auth::class, HandleCors::class]], function () {
    $requestJson = Request::capture()->json();
    $requestMethod = $requestJson->get('method', false);
     // ...
});

and the test:

$response = $this->json('POST', '/api/v0/', [
            'method' => 'user/login',
            'email' => '[email protected]',
            'password' => 'passwd'
        ]);

I traced it down into Illuminate\Foundation\Testing\Concerns\MakesHttpRequests and at the following:

$response = $kernel->handle(
            $request = Request::createFromBase($symfonyRequest)
        );

The Request::createFromBase object still appears to contain my json content. So I'm just not understanding why Request::capture() in the route file does not contain that content.

Any suggestions greatly appreciated.

Thanks!

0 likes
4 replies
bobbybouwmann's avatar

Not really sure what you're trying to do right now. Laravel will handle posted json just fine and you can use the normal $request->get('field') calls as far as I know.

Retrieving JSON Input Values

When sending JSON requests to your application, you may access the JSON data via the input method as long as theContent-Type header of the request is properly set to application/json. You may even use "dot" syntax to dig into JSON arrays:

$name = $request->input('user.name');

Documentation: https://laravel.com/docs/5.6/requests#input-trimming-and-normalization

brianh's avatar

Thanks for the response. I'm trying to replace an existing (old/crappy) API with a laravel API without requiring any changes to the front end client. The client currently sends all API requests as POSTs to a single endpoint with a json body containing a "method" (user/login from my example above) and other data.

My routes/api.php file is parsing the json of the request for routing something like "method": "user/login" to UserController@login

It is indeed handling the JSON posts just fine when I make requests via Postman, but when I try to run phpunit with tests making the requests it does not appear to get that json body/content.

Route::group(['prefix' => 'v0', 'middleware' => [V0Auth::class, HandleCors::class]], function () {
    var_dump(request()->input('method'));
    exit();
    // parse the request json for the "method" and route to an appropriate Controller@action

When I make a request with Postman, I see the expected "user/login", but running the test with the same request (as far as I can tell) results in NULL.

Maybe I'm overthinking/complicating and doing something dumb, or just missing something. I'm just trying to understand why the request seems to be different. Here's the raw request in Postman that works:

POST /api/v0/ HTTP/1.1
Host: [redacted]
Content-Type: application/json
Accept: application/json
Cache-Control: no-cache
Postman-Token: 4b6e7540-79ff-4249-b7f8-6e3847758a45

{
    "method": "user/login",
    "email": "[email protected]",
    "password": "passwd"
}

I would think this code would result in the same request (and response):

$response = $this->json('POST', '/api/v0/', [
            'method' => 'user/login',
            'email' => '[email protected]',
            'password' => 'passwd'
        ]);

Thanks again! Brian

brianh's avatar

Looks like the issue is that route creation logic is called during the TestCase createApplication step, which is before the request is crafted by $this->json() -- so my dynamic routing using the json content does not work.

brianh's avatar
brianh
OP
Best Answer
Level 5

Final post... I solved my issue by using the vanilla PHP Unit TestCase instead of Laravel's. I'm sure I'm losing out on some nice helpers, but this works:

<?php

namespace Tests\Feature;

use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

class UserTest extends TestCase
{
    public function testUserLogin()
    {
        $client = new Client();
        $response = $client->post('url', [
            RequestOptions::JSON => [
                'method' => 'user/login',
                'email' => '[email protected]',
                'password' => 'passwd'
            ]
        ]);
        // assertions against $response->getBody();
    }
}

Please or to participate in this conversation.