Route Parameters

Most real routes need to capture part of the URL as data — a user ID, a product slug, and so on. Slim lets you define these dynamic segments right inside the route pattern using curly braces.

Dynamic Segments with Curly Braces

Wrap a placeholder name in { } anywhere in the route path:

$app->get('/users/{id}', function ($request, $response, $args) {
    $id = $args['id'];
    $response->getBody()->write("Showing user " . $id);
    return $response;
});

A request to /users/42 matches this route and Slim populates $args with ['id' => '42']. Note that placeholder values always arrive as strings — cast with (int) if you need a number.

Reading Values from $args

Every named placeholder in the route becomes a key in the $args array, in the third parameter of your handler closure — you simply index into it by name:

$name = $args['id']; // value from the matched {id} segment

Optional Parameters

Wrap a trailing segment in square brackets to make it optional. If the visitor omits it, the argument simply won't be present in $args:

$app->get('/greet/{firstName}[/{lastName}]', function ($request, $response, $args) {
    $greeting = "Hello, " . $args['firstName'];
    if (isset($args['lastName'])) {
        $greeting .= " " . $args['lastName'];
    }
    $response->getBody()->write($greeting);
    return $response;
});

Both /greet/Sonu and /greet/Sonu/Pandit match this single route definition.

Constraining a Parameter with a Regex Pattern

Append :pattern after the placeholder name to restrict what it can match. This is useful for making sure an id segment only matches digits, so it doesn't accidentally swallow other routes:

$app->get('/users/{id:[0-9]+}', function ($request, $response, $args) {
    $response->getBody()->write("Numeric user ID: " . $args['id']);
    return $response;
});

With this pattern, /users/42 matches but /users/abc does not — Slim will fall through to a 404 (or another matching route) instead of running this handler with bad data.

Worked Example: Two Parameters in One Route

Routes can capture more than one dynamic segment. Here both a product ID and a review ID are read from the URL:

$app->get('/products/{id:[0-9]+}/reviews/{reviewId:[0-9]+}', function ($request, $response, $args) {
    $productId = $args['id'];
    $reviewId = $args['reviewId'];

    $response->getBody()->write(
        "Review " . $reviewId . " for product " . $productId
    );
    return $response;
});

A request to /products/7/reviews/103 matches, and $args holds ['id' => '7', 'reviewId' => '103'] — both readable by name inside the handler.

Next steps: Continue to Request & Response to explore the full PSR-7 request and response objects — query strings, POST bodies, headers, and status codes.