Backend Development – Custom Routes

In Drupal, routes are the entry point to backend logic.

Every page, controller, form, AJAX callback, or JSON response starts with a route. If custom modules define what behavior exists, routes define how a request reaches that behavior.

This article is the second article in the Level 2 – Backend Development series.

By the end of this article, you will understand:

  • What a route is in Drupal
  • How Drupal matches URLs to backend code
  • Required and optional route keys
  • How access control works at the routing level
  • How routes fit into Drupal’s request lifecycle

1. What Is a Route (Simple Explanation)

A route tells Drupal:

  • Which URL path to listen to
  • What backend code should handle the request
  • Who is allowed to access it

In plain terms:

A route is a map between a URL and backend logic.

Without routes, controllers, forms, and APIs cannot be reached.


2. Where Routes Are Defined

Routes are defined in a YAML file named:

MODULE_NAME.routing.yml

For our example module:

weeklydrupal_demo.routing.yml

Drupal discovers this file automatically when the module is enabled.


3. The Basic Route Structure

A minimal route definition looks like this:

weeklydrupal_demo.page:
  path: '/weeklydrupal/demo'
  defaults:
    _controller: '\\Drupal\\weeklydrupal_demo\\Controller\\DemoController::page'
    _title: 'WeeklyDrupal Demo'
  requirements:
    _permission: 'access content'

Each route has three core parts:

  • Route name
  • Path
  • Handler and access rules

4. Route Name (Why It Matters)

weeklydrupal_demo.page:

This is the route machine name.

Rules:

  • Must be unique across the site
  • Usually starts with the module name
  • Used internally by Drupal (links, redirects, access checks)

Example usage:

  • Url::fromRoute('weeklydrupal_demo.page')
  • Menu links and tasks reference route names

5. Path (The URL)

path: '/weeklydrupal/demo'

This is the URL users visit in the browser.

Guidelines:

  • Paths should be human-readable
  • Admin paths usually start with /admin
  • Avoid hardcoding language prefixes

Drupal automatically handles language and base paths.


6. Defaults Section (What Runs)

defaults:
  _controller: '\Drupal\weeklydrupal_demo\Controller\DemoController::page'
  _title: 'WeeklyDrupal Demo'

_controller

  • Points to a PHP class and method
  • Uses the full namespace
  • Format: ClassName::methodName

Drupal will:

  1. Autoload the class
  2. Instantiate it
  3. Call the method

_title

  • Sets the page title
  • Can be a string or a callback
  • Can be overridden dynamically later

7. Requirements Section (Access Control)

requirements:
  _permission: 'access content'

This controls who can access the route.

Common requirement keys:

  • _permission – Check a permission string
  • _role – Restrict by user role
  • _custom_access – Custom access logic

If access fails, Drupal returns a 403 response automatically.


8. Route Access Is Checked Before Code Runs

Important concept:

If access fails, the controller is never executed.

This means:

  • Security is enforced early
  • Backend code stays clean
  • Access logic does not belong in controllers

Drupal encourages declarative access control at the routing level.


9. Route Parameters (Dynamic URLs)

Routes can accept parameters:

weeklydrupal_demo.item:
  path: '/weeklydrupal/demo/{id}'
  defaults:
    _controller: '\\Drupal\\weeklydrupal_demo\\Controller\\DemoController::item'
  requirements:
    id: '\\d+'
    _permission: 'access content'

Drupal will:

  • Extract {id} from the URL
  • Pass it as a method argument

Example controller method:

public function item($id) {
  return [
    '#markup' => 'Item ID: ' . $id,
  ];
}

10. How Routes Fit Into the Request Lifecycle

Simplified flow:

  1. HTTP request arrives
  2. Drupal matches the URL to a route
  3. Access checks are evaluated
  4. Controller or form is executed
  5. Render array is returned
  6. Response is generated

Routes are the gateway into backend Drupal.


11. Common Mistakes to Avoid

  • Hardcoding URLs instead of using route names
  • Performing access checks inside controllers
  • Mixing routing logic with business logic
  • Forgetting to clear caches after changing routes

Routes are cached aggressively. Always rebuild cache after changes.


12. Learning by Building: Extending weeklydrupal_demo

In this topic, our module now supports:

  • A static page route
  • A parameterized route
  • Permission-based access control

Future topics will reuse these routes for:

  • Forms
  • AJAX callbacks
  • Admin pages
  • API responses

13. Why Custom Routes Matter

If you understand routes:

  • Controllers feel predictable
  • Forms make sense
  • Menu links become trivial
  • Access control becomes consistent

Routes define the shape of your backend system.