Request & Response

Every Slim route handler works with two objects: an incoming request and an outgoing response. Both implement PSR-7, the PHP-FIG standard interface for HTTP messages. In practice, that means any library written to work with "a PSR-7 request" or "a PSR-7 response" can work with Slim's objects too — and Slim's objects would work with any other PSR-7-compatible framework or library. It's a shared contract, not something specific to Slim.

Reading Query String Parameters

For a URL like /search?q=slim&page=2, pull the query parameters as an associative array:

$app->get('/search', function ($request, $response, $args) {
    $params = $request->getQueryParams();
    $query = $params['q'] ?? '';
    $page = $params['page'] ?? '1';

    $response->getBody()->write("Searching for '" . $query . "', page " . $page);
    return $response;
});

Reading POST and JSON Body Data

For traditional form submissions (application/x-www-form-urlencoded or multipart/form-data), Slim parses the body for you automatically:

$app->post('/login', function ($request, $response, $args) {
    $data = $request->getParsedBody();
    $username = $data['username'] ?? '';

    $response->getBody()->write("Logging in: " . $username);
    return $response;
});

For a raw JSON body, getParsedBody() only works if the Content-Type header is set correctly and a parser is registered — it's often simpler to decode it yourself:

$app->post('/api/users', function ($request, $response, $args) {
    $data = json_decode((string)$request->getBody(), true);
    $email = $data['email'] ?? null;

    $response->getBody()->write("New user email: " . $email);
    return $response;
});

Casting the body to (string) reads the whole PSR-7 stream, and true as the second json_decode argument returns an associative array instead of an object.

Reading Headers

Read a single header's value as a plain string with getHeaderLine():

$contentType = $request->getHeaderLine('Content-Type');

This is handy for branching logic based on what the client sent — for example, deciding whether to run getParsedBody() or your own JSON decoding.

Setting a Status Code and Header on the Response

Chain withStatus() and withHeader() to shape the outgoing response, for example when returning a freshly created JSON resource:

$app->post('/api/users', function ($request, $response, $args) {
    $payload = json_encode(['status' => 'created']);
    $response->getBody()->write($payload);

    return $response
        ->withStatus(201)
        ->withHeader('Content-Type', 'application/json');
});
The "with" prefix matters: withStatus() and withHeader() do not modify $response in place — they each return a brand-new response object with that one change applied, leaving the original untouched. This is PSR-7's immutability principle. That's why the example above chains the calls and returns the final result directly: if you called $response->withStatus(201); on its own line without capturing or returning the result, the change would be thrown away.
Next steps: Continue to Middleware to see how you can run shared logic — like authentication or logging — before and after your route handlers.