Inbound & Outbound Processing

Understanding Inbound and Outbound Processing in Drupal: Principles and Examples

Introduction

In a Drupal site, when a user interacts with the system (for example, by accessing a URL, submitting a form, or consuming an API), Drupal processes the request through an entry and exit cycle — this is what we call Inbound and Outbound processing.

These two mechanisms allow Drupal to:

  • Interpret incoming data (inbound),
  • Modify outgoing data (outbound),
  • And centralize processing logic via services or hooks.

Let us look at all of this in detail with concrete examples.

1. Inbound Processing: Handling What Comes In

Inbound Processing applies to everything the user sends to the system:

  • The requested URL,
  • Query parameters (GET, POST),
  • Data submitted in a form or API call.

Goal

  • Rewrite paths or parameters,
  • Apply transformation or security logic,
  • Decode values before they are used by the system.

Example: Modifying an Incoming URL

Imagine we want to redirect paths /products to /product while keeping Drupal's internal logic intact.

use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class InboundPathSubscriber implements EventSubscriberInterface {

  public static function getSubscribedEvents() {
    return ['kernel.request' => ['onKernelRequest', 30]];
  }

  public function onKernelRequest(RequestEvent $event) {
    $request = $event->getRequest();
    $path = $request->getPathInfo();

    if ($path === '/products') {
      $request->server->set('REQUEST_URI', '/product');
    }
  }
}

Here, we use the kernel.request event to intercept the URL before Drupal resolves the router.

2. Outbound Processing: Manipulating What Goes Out

Outbound Processing occurs when Drupal generates a response (HTML, JSON, etc.). It is often used to:

  • Modify generated links (Url::fromRoute()),
  • Dynamically rewrite outgoing URLs,
  • Add HTTP headers, or modify the JSON structure.

Example: Dynamic Link Rewriting

Suppose you want to transform all /user/ID links into /profile/ID during HTML rendering:

use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Render\BubbleableMetadata;

class OutboundPathProcessor implements OutboundPathProcessorInterface {
  public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    if (strpos($path, '/user/') === 0) {
      return str_replace('/user/', '/profile/', $path);
    }
    return $path;
  }
}

Declaration in services.yml:

services:
  my_module.path_processor.outbound:
    class: Drupal\my_module\OutboundPathProcessor
    tags:
      - { name: path_processor_outbound, priority: 100 }

When to Use Inbound vs Outbound?

Situation Inbound Outbound
Modify the path before it is resolved Yes No
Modify a link before displaying it No Yes
Rewrite URL parameters Yes Yes
Add HTTP headers No Yes
Handle conditional redirection Yes No

Combined Use: A Typical Multilingual Site Scenario

  • Inbound: intercept the URL /fr/products to route to /en/product.
  • Outbound: generate properly translated links in menus (/fr/products, /en/product...).

PathProcessorManager orchestrates these operations in Drupal Core.

Debugging & Best Practices

  • Use \Drupal::logger() to trace processed paths.
  • Prioritize your Symfony event subscriptions (execution order is critical).
  • Enable route caching in production but disable it during development.

Conclusion

The Inbound and Outbound systems in Drupal are powerful tools for controlling the flow of HTTP data. Whether you are building a multilingual site, a headless site, or simply want to customize your site's paths, these hooks give you fine-grained control over data entry and exit — without modifying Drupal core.