Route Groups
As an app grows, you'll often have several routes that share the same URL prefix — for example, every route under /api or every admin route under /admin. Slim lets you collect these related routes into a route group so the shared prefix (and any shared middleware) is written once instead of repeated on every route.
Creating a Group
Call $app->group() with the common prefix and a callback. Inside the callback you define routes on the $group object instead of $app — Slim automatically prepends the group's prefix to each one.
<?php
$app->group('/api', function ($group) {
$group->get('/status', function ($request, $response) {
$response->getBody()->write('OK');
return $response;
});
});
The route above is reachable at /api/status — the /api prefix came entirely from the group, so it never has to be typed again inside the callback.
Applying Middleware to a Whole Group
Just like a single route, a group can have middleware attached with ->add(). This runs the middleware for every route inside that group — a common use case is requiring authentication for all /admin routes without adding the check to each one individually.
<?php
$requireAdmin = function ($request, $handler) {
// Check session, token, etc. before letting the request continue
if (!isset($_SESSION['is_admin'])) {
throw new \Slim\Exception\HttpForbiddenException($request);
}
return $handler->handle($request);
};
$app->group('/admin', function ($group) {
$group->get('/dashboard', function ($request, $response) {
$response->getBody()->write('Admin dashboard');
return $response;
});
})->add($requireAdmin);
Worked Example: Grouping a REST Resource
Grouping shines when a single resource — like users — needs several HTTP methods (GET, POST, PUT, DELETE). Instead of repeating '/api/users' on every line, the prefix is declared once.
<?php
$app->group('/api/users', function ($group) {
// GET /api/users - list all users
$group->get('', function ($request, $response) {
return $response;
});
// POST /api/users - create a user
$group->post('', function ($request, $response) {
return $response;
});
// PUT /api/users/{id} - update one user
$group->put('/{id}', function ($request, $response, $args) {
return $response;
});
// DELETE /api/users/{id} - remove one user
$group->delete('/{id}', function ($request, $response, $args) {
return $response;
});
});
Four routes, one resource, one prefix declared a single time. Read together, this block reads almost like documentation of everything the /api/users endpoint can do.
Why Bother Grouping?
| Benefit | Why it helps |
|---|---|
| Less repetition | The shared prefix is written once instead of on every route |
| Shared middleware | Auth checks, logging, or rate limiting can apply to a whole section of the app at once |
| Readability | Related endpoints are visually and logically grouped together in the code |
| Easier refactoring | Changing a prefix (e.g. /api to /api/v1) means editing one line |