Skip to content

Routing Concept

  • Routing is the process of redirecting requests to the appropriate code that should handle them.
    • When a user navigates to a URI (such as /users or /products), the routing system in modern web applications maps that URI to the specific controller method responsible for handling the request.
  • Think of routing as a traffic controller that directs incoming requests to their designated handlers based on the URI pattern and HTTP method.

Without routing, web applications would be impossible to maintain and organize. Here’s why routing is essential:

  • Before routing: All code mixed together in one file, making it impossible to maintain and organize.
  • With routing: Each URI has its own specific handler, creating clean separation of concerns.
  • Before routing: Ugly URIs like index.php?page=users&action=view&id=123 (bad for SEO).
  • With routing: Clean URIs like /users/123 that are easy to read and remember.
  • GET /products → Show list of all products (GET request)
  • GET /products/123 → Show specific product with ID 123
  • POST /products → Create a new product

Routing enables consistent URI patterns, making your application predictable and easy to navigate.

  • Only allow specific URIs to be accessed.
  • Different permissions for different routes.
  • Easy to protect sensitive areas of your application.

Each route maps a specific URI pattern and HTTP method to a handler that processes the request. A route consists of:

  1. HTTP method: The HTTP method (GET, POST, PUT, DELETE, etc.) used by the client to make the request.
  2. URI pattern: The URI pattern that the route matches.
  3. Handler function: The function or controller method that processes the request.

Modern routing systems distinguish between different HTTP methods (GET, POST, etc.) for the same URI path. For example, a route might handle both GET and POST requests to the same URI.

  • GET: Retrieve data from the server.
  • POST: Create a new resource on the server.

Routes are associated with specific URI patterns. These patterns can be:

  1. Static: Exact paths, e.g., /about, /contact.
  2. Dynamic (with parameters): Paths like /users/{id}, where {id} is a placeholder for a variable value.
  3. Wildcard: Patterns like /files/*, which match any path segment after a certain point.

Each route is linked to a handler function or controller method, which contains the logic to process the request and generate a response. The response could be:

  • An HTML page
  • JSON data
  • A file download
  • A redirect

  • Route caching: Production applications often cache compiled routes for better performance.
  • Route model binding: Some frameworks automatically resolve route parameters to model instances.
  • Named routes: Routes can be given names for easier URI generation in templates and redirects.
  • Route constraints: Parameters can have validation rules (regex patterns, type constraints).

When a request comes in, Slim’s router:

  1. Matches the HTTP method (GET, POST, etc.),
  2. Compares the URI path against defined route patterns,
  3. Extracts parameters from the URI if the route has placeholders
  4. Executes middleware if any is defined for the route,
  5. Calls the route handler with the request, response, and extracted parameters,
  6. Returns the response to the client.

First, let’s set up a basic Slim application:

<?php
require_once 'vendor/autoload.php';
use Slim\Factory\AppFactory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
// Create Slim app instance
$app = AppFactory::create();
// Your routes go here...
// Run the application
$app->run();

The most basic route responds to GET requests:

$app->get('/', function (Request $request, Response $response, $args) {
$response->getBody()->write("Welcome to the homepage!");
return $response;
});
// Simple GET route
$app->get('/dashboard', function (Request $request, Response $response, $args) {
$response->getBody()->write("Welcome to the dashboard!");
return $response;
});

Handle form submissions with POST routes:

$app->post('/contact', function (Request $request, Response $response, $args) {
$parsedBody = $request->getParsedBody();
$name = $parsedBody['name'] ?? '';
$email = $parsedBody['email'] ?? '';
// Process form data here
$response->getBody()->write("Thank you " . $name . " for contacting us!");
return $response;
});

Capture dynamic parts of URIs using curly braces:

$app->get('/user/{id}', function (Request $request, Response $response, $args) {
$userId = $args['id'];
$response->getBody()->write("User ID: " . $userId);
return $response;
});

Make parameters optional using square brackets (optional parameters):

$app->get('/products[/{category}]', function (Request $request, Response $response, $args) {
$category = $args['category'] ?? 'all';
$response->getBody()->write("Showing products in category: " . $category);
return $response;
});

Add validation rules using regular expressions (parameter constraints):

$app->get('/article/{id:[0-9]+}', function (Request $request, Response $response, $args) {
$articleId = $args['id'];
$response->getBody()->write("Article ID: " . $articleId);
return $response;
});

Organize related routes with common prefixes (route groups):

$app->group('/admin', function ($group) {
$group->get('/dashboard', function (Request $request, Response $response, $args) {
// Display admin dashboard
$response->getBody()->write("Welcome to the Admin Dashboard");
return $response;
});
$group->get('/users', function (Request $request, Response $response, $args) {
// Display user management page
$response->getBody()->write("User Management Panel");
return $response;
});
$group->get('/settings', function (Request $request, Response $response, $args) {
// Display admin settings
$response->getBody()->write("Admin Settings Panel");
return $response;
});
$group->post('/users/{id}/ban', function (Request $request, Response $response, $args) {
$userId = $args['id'];
// Ban user logic here
$response->getBody()->write("User " . $userId . " has been banned");
return $response;
});
});

Add functionality that runs before your route handlers:

$app->add(function (Request $request, Response $response, $next) {
$response = $next($request, $response);
return $response->withHeader('X-Custom-Header', 'My Custom Value');
});

Handle 404 errors and other unmatched routes:

$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function($request, $response) {
$response->getBody()->write('404 - Page not found');
return $response->withStatus(404);
});