Pragmatism in the real world

Receiving input into a Slim 4 application

A Slim 4 (and Slim 3) application receives data from three places:

  • Any query parameters on the URL (the key-value pairs after the ?)
  • The HTTP message’s body (usually for POST and PUT) messages
  • Parameters in the URL (such as the 3 in https://example.com/users/3

Within the application, these are available within the PSR-7 Request object.

Let’s start with a simple Slim 4 application.

Firstly we require the Slim framework and a PSR-7 implementation:

$ composer require slim/slim slim/psr7

Now we write public/index.php:

<?php declare(strict_types=1);

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);

$app->get('/', function (Request $request, Response $response, $args): Response {
    // our code for this handler goes here

    return $response;
});

$app->run();

This is the standard minimal Slim 4 application, which will respond solely to the / URL (i.e. the home page of the website) and will return an empty response. See A first look at Slim 4 for more information.

We can run our website with:

$ php -S 0.0.0.0:8888 -t public/

If we navigate to https://localhost:8888 we’ll see a blank page.

Query parameters

Query parameters are the key value pairs after the ? in the URL. For example in the ULR http://localhost:8888?name=Rob, we have a parameter name with the value Rob.

To access this in our Slim 4 handler, we use the Request’s getQueryParams() method. This will return an array of all query parameter.

i.e. if we add:

// our code for this handler goes here
$params = $request->getQueryParams()
var_dump($params);

And then navigate to localhost:8888/?name=Rob&country=UK, we will see:

array (size=1)
  'name' => string 'Rob' (length=3)
  'country' => string 'UK' (length=2)

Note that the PSR-7 RequestInterface doesn’t have a method to retrieve a single parameter, so if you just want a one parameter, the easiest way is to use the null coalescing operator (??) like this:

$name = $request->getQueryParameters()['name'] ?? '';

This will either set $name to the value of the name query parameter if it exists or set it to an empty string otherwise

Posted form data

For form data posted to the website from a browser, we can use the $request’s getParsedBody() method. This will return an array of the posted data.

Firstly we set up a form:

$app->get('/', function (Request $request, Response $response, $args): Response {
    $html = <<<HTML
<html>
    <form method="POST">
        <label>Name: <input name="name"></label>
        <label>Country: <input name="country"></label>
        <input type="submit">
    </form>
</html>
HTML;
    $response->getBody()->write($html);
    return $response;
});

We also need a handler to receive the POSTed data:

$app->post('/', function (Request $request, Response $response, $args): Response {
    $data = $request->getParsedBody();
    $html = var_export($data, true);
    $response->getBody()->write($html);
    return $response;
});

If we fill out our form with the same name and country as before:

2019 09 01 simple form

(HTML/CSS isn’t really my forté!)

we’ll get:

array ( 'name' => 'Rob', 'country' => 'UK', )

Again, the PSR-7 Request object doesn’t have a method to retrieve a single parameter from POSTed data, but in my experience this is rarely a requirement anyway.

POSTed JSON or XML data

It’s very common in web APIs to send data in XML or JSON format. Out of the box, PSR-7 implementations do not support these formats, you have to decode the Request object’s getBody() yourself. As this is a common requirement, Slim 4 provides BodyParsingMiddleware to handle this task.

This is added using:

$app->addBodyParsingMiddleware();

And can be added anywhere in the middleware stack and I usually put it before before the call to addErrorMiddlware, so that my stack looks like this:\

$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
$app->addErrorMiddleware(true, true, true);

With this added, we can use curl to prove it works:

$ curl -H "Content-type: application/json" \
  -d '{"name": "Rob", "country": "UK"}' \
  http://localhost:8888/

array (
  'name' => 'Rob',
  'country' => 'UK',
)

No changes are required to the POST handler because BodyParsingMiddleware detects that the content-type is set to a JSON media type and so places the decoded body into the Request’s parsed body property.

URL parameters

For web APIs and dynamic websites, it is very common to use the URL as a way to accept parameters into the application. This is done by treating a segment of the URL (i.e. between two /) as a value. For example we may have a URL of /UK/Rob and want to access the UK and Rob as the parameters country and name respectively.

As Slim 4 uses FastRoute, we do this by creating a pattern when defining the URL in the App’s HTTP method methods such as get() & post().

For this example, we would create a route like this:

$app->get(
    '/{country}/{name}', 
    function (Request $request, Response $response, $args
): Response {
    // our code for this handler goes here
    return $response;
});

In the URL pattern, we use braces around a key name to indicate that this is a parameterised segment, so '/{country}/{name}' defines two such segments. Note that if we wanted to make them optional, then we would enclose in square brackets like this: '/[{country}[/{name}]]'.

The parameterised values are provided to our hander in two different places. Firstly, they are in the $args array, so if we add:

var_dump($args)

And navigate to http://localhost:8888/UK/Rob, we see:

array (size=2)
  'country' => string 'UK' (length=2)
  'name' => string 'Rob' (length=3)

Secondly, they are also assigned as attributes to the Request object, so we can also do:

$country = $request->getAttribute('country');
$name = $request->getAttribute('name');

Be careful of using $request->getAttributes() as this will return all attribute, not just parameterised values from the URL.

That’s it

As a PSR-7 based framework, receiving data into a Slim 4 application works very similarly to any other PSR-7 framework and the key object as you’d expect is the Request object.

Slim 4’s handling is essentially the same as Slim 3. There are some detail differences around setting up body parsing which is enabled by default in Slim 3, but other than that, accessing the data your user has sent you should be very familiar.

3 thoughts on “Receiving input into a Slim 4 application

  1. Hi Rob,

    I'd be really interested in how to go about a POST endpoint for lists of records in Slim 4 if it's something you would enjoy writing about.

    Currently torn between standard HTML and JSON array of Objects.

  2. OMG. Thank you. I've been searching why my application is not getting json raw body.
    And just one line fixed it
    $app->addBodyParsingMiddleware();

  3. It is very useful; many thanks for sharing, I read the documentation, but I did not see anything about $app->addBodyParsingMiddleware();

    I think I did not read very well XD.

Comments are closed.