The Slim documentation makes it abundantly clear that Response
objects are immutable: each method that accepts a Response
as an argument returns a copy of that object. You can also puzzle out that methods like withHeader()
and withStatus()
can be chained together. And the docs explain how to use withJson()
if you want your endpoint's payload to be JSON and you're content with the default MIME type.
What is not so well explained: that getBody()->write()
does not return a Response
, so it can't be chained. Nor is it clear how to use these methods when you want to set your own MIME type ("application/hal+json", in my case) or status code. Hence, this example, somewhat simplified.
The GET /short
endpoint returns a brief HAL representation of the resource identified by :id
.
namespace Demo;
class Controller {
/**
* GET /short/:id
*
* @param \Slim\Http\Request $request
* @param \Slim\Http\Response $response
* @param string[] $args
* @return \Slim\Http\Response
*/
public function short($request, $response, $args) {
$id = $args['id'];
try {
$guid = ...; //look up info about $id
if (empty($guid)) {
Logger::warning("No info for $id");
return $response->withStatus(404);
}
$doc = ...; // construct a model, using $guid
$rsp = $response->withAddedHeader('Content-type', 'application/hal+json');
$rsp->getBody()->write(json_encode($doc->getDocArray()));
return $rsp;
}
catch (Exception $e) {
Logger::warning($e->getMessage()." Failed");
return $response->withStatus(500);
}
}
}
And how do you write a unit test for this endpoint? Likewise, the docs give some strong hints, but leave you to connect the dots. The trick is to use Environment::mock()
to get an object that can be passed to a factory method on Request
. A simplified version of my happy-path unit test:
class ControllerShortTests extends \PHPUnit_Framework_TestCase
{
/** @var \Slim\Http\Request */
private $request;
/** @var \Slim\Http\Response */
private $response;
/** @var string[] */
private $args;
/** @var \Slim\Container */
private $container;
/** @var \Demo\Controller */
private $controller;
public function setUp()
{
$this->request = \Slim\Http\Request::createFromEnvironment(\Slim\Environment::mock());
$this->response = new \Slim\Http\Response();
$this->args = [];
$this->container = new \Slim\Container();
... // set up a mock datastore provider
$this->controller = new \Demo\Controller($this->container);
}
public function testExpectSuccess()
{
... // configure the provider
$this->args['id'] = 987654321;
$response = $this->controller->short($this->request, $this->response, $this->args);
$this->assertEquals(200, $response->getStatusCode(), 'Wrong status');
... // and more assertions
}
}