Search code examples
phphttp-headersguzzle

Why are the headers empty?


I am trying to get a simple redirection to work with GuzzleHttp and am using phpunit to test my code. The expected behavior is that if the requested URL ends with a "/" then the response should be a redirection to the same URL stripped with the trailing "/".

This is how my App.php looks like :

<?php
namespace Framework;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class App {
    public function run(ServerRequestInterface $request): ResponseInterface {
        $uri= $request->getUri()->getPath();
        if (!empty($uri) && $uri[-1] === "/") {
            $response= new Response();
            $response= $response->withStatus(301);
            $response= $response->withHeader('Location', substr($uri, 0, -1));
        }
        $response= new Response();
        $response->getBody()->write('Hello.');
        return $response;
    }
}

And I run the test in AppTest.php like this :

<?php
namespace Tests\Framework;

use Framework\App;
use GuzzleHttp\Psr7\ServerRequest;
use PHPUnit\Framework\TestCase;

class AppTest extends TestCase {
    public function testRedirectTrailingSlash() {
        $app= new App();
        $request= new ServerRequest('GET', '/some-slug/');
        $response= $app->run($request);
        $this->assertContains('/some-slug', $response->getHeader('Location'));
        $this->assertEquals('301', $response->getStatusCode());
    }
}

When I run this test, both assertions fail and it's due to the fact that the response's status code is 200 and the headers list is empty and I confirmed that by doing a var_dump().

The weirdest thing is that, I wrote this code a few months ago and it worked and as far as I remember, the only thing I did between then and now was a composer install so I don't know if it's due to a recent updates of the dependencies.

Can someone help me with this?


Solution

  • The issue seems to stem from the fact that you are always creating a new response object right after setting the redirection headers. This overwrites the previous response that had the redirection.

    To fix this, either return the created response before closing the if statement or put the rest of the code inside an else to avoid overwriting your previous response object like the other answer. Try the below code in your App.php:

    <?php
    namespace Framework;
    use GuzzleHttp\Psr7\Response;
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    
    class App {
        public function run(ServerRequestInterface $request): ResponseInterface {
            $uri = $request->getUri()->getPath();
            if (!empty($uri) && $uri[-1] === "/") {
                $response = new Response();
                $response = $response->withStatus(301);
                $response = $response->withHeader('Location', substr($uri, 0, -1));
                return $response; 
            }
    
            $response = new Response();
            $response->getBody()->write('Hello.');
            return $response;
        }
    }