# Mvc And Request Handling

> How a web request is routed and handled: MVC's actual division of responsibilities, Page Controller versus Front Controller, and Application Controller for flows whose next step is a decision. Use when controllers contain business rules or persistence calls, when the same cross-cutting concern is copied into every handler, when a wizard's navigation logic is spread across handlers as if-chains, when a filter, interceptor and handler contend for one concern, when a controller is tested by starting the whole application, or when classical web patterns are mapped onto a REST API. Does not cover how the response is rendered (view-and-representation-patterns), the remote operation and its payload (remote-facade-and-dto), the use-case layer (service-layer-design), or where conversation state lives across requests (session-state-strategies).

- Skill: `robsonkades/mvc-and-request-handling` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add robsonkades/mvc-and-request-handling`
- Raw SKILL.md: https://api.skillmd.com/api/skills/robsonkades/mvc-and-request-handling/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: robsonkades (https://skillmd.com/u/robsonkades)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/robsonkades/mvc-and-request-handling

---


# MVC and Request Handling

## Purpose

Keep the web layer to its actual job — turning a request into a call and a result into a
response — and put shared request concerns in one place instead of in every handler. Modern
frameworks implement these patterns for you, so the value here is not in building them but
in **recognising which pattern a piece of code is playing**, and noticing when a
responsibility has landed in the wrong one.

## The vocabulary, disambiguated

"Model" means three different things in a typical discussion, and conflating them causes
real design errors:

```text
Domain model        the business objects and rules (domain-logic-organization)
Presentation model  what the view needs: already formatted, already decided
Framework model     the map of attributes handed to a template (Spring's Model)
```

The separation used here for a web boundary:

```text
Controller   interprets the request, invokes the application, selects the response.
             Delegates business rules and use-case transaction ownership.
View         renders. Owns no decisions beyond presentation.
Model        application state/behavior in MVC's broader vocabulary;
             prefer a deliberate presentation model at the response boundary.
```

Web MVC is not the original Smalltalk MVC: there is no observer relationship and no
long-lived view. The name persists; the mechanism is request → controller → model → render.

## Page Controller and Front Controller

```text
Page Controller      one handler per page or action. Simple, local, and every
                     shared concern needs a shared mechanism such as filters
                     or composed collaborators.

Front Controller     one entry point receives every request, applies shared
                     concerns, and dispatches to a handler. Shared concerns
                     exist once; the handler stays small.
```

Many Java web frameworks provide a Front Controller (for example Spring's `DispatcherServlet`),
and handler methods play the page/action role behind it. These patterns can coexist.
The practical questions are **which
concerns belong in the front controller's chain and which in the handler**, and whether the
chain's stages are being used correctly.

## Workflow

1. **Check the handler's contents and runtime.** Inspect routing, security configuration,
   Java and framework versions first. Examples use Servlet Spring MVC; `ProblemDetail`
   requires Spring 6+ (Java 17+), not an implicit upgrade. A controller should bind input,
   invoke application behavior, and map the result. Trace business rules and transaction
   ownership; a simple read need not gain a pass-through service (`layering-and-boundaries`).
2. **Find duplicated policy.** Repetition count alone does not justify indirection; shared
   authorization, error mapping, correlation, tenant and envelope semantics often belong in the
   chain when centralization prevents drift and preserves ordering.
3. **Place it at the right stage.** Filter, interceptor, argument resolver, exception
   handler, advice: they see different things and run at different times. Choosing wrongly
   produces a concern that works until it does not.
4. **Extract flow decisions.** If a handler decides which step comes next based on
   application state, that is an Application Controller and it belongs outside the web
   layer.
5. **Keep the response shape a deliberate decision**, not the accidental serialisation of
   whatever the service returned (`remote-facade-and-dto`).
6. **Test at the right level.** Handler tests should not need a database; the mapping,
   validation and status codes are what the web layer is responsible for.

## Decision rules

```text
A concern applies to every request (correlation id, security context,
request logging, tenant resolution)
        → the front controller's chain: a filter, before routing.

A concern applies to a group of handlers and needs to know which handler
was selected (authorisation on an annotation, feature flags per route)
        → enabled method security for authorisation; an interceptor can
          handle non-security route metadata. Keep request security in
          the security filter chain, with consistent path matching.

A concern turns an exception into a response
        → consistent error mapping at each boundary: MVC advice for MVC
          exceptions, security/filter/container handlers for their failures.
          Share the contract; avoid duplicated generic catches.

A concern turns request data into a domain-shaped parameter
(the current user, a parsed range, a tenant)
        → an argument resolver. This removes the boilerplate without
          hiding a business rule.

The next step of a multi-step flow depends on state, not on a link
        → Application Controller: a class that owns the flow, outside
          the web layer, testable without HTTP.

A screen is one page, one action, no shared concerns beyond the global
ones
        → a plain handler. Do not build a flow abstraction for it.

The API is REST over resources
        → routing is by resource and method, not by page. Page
          Controller and Front Controller both still describe what the
          framework does; the patterns to reach for are Remote Facade
          and DTO, not Two Step View.
```

## Rules

- A controller deciding domain policy is a layering defect; `if` itself is not evidence because
  protocol negotiation, optional input and response mapping legitimately branch. Trace whether the
  condition must hold for non-HTTP callers.
- **A controller with a repository call is not automatically wrong.** For a pure read it can
  be the honest design; for anything that writes, it puts the transaction boundary and the
  invariants in the web layer (`service-layer-design`).
- Cross-cutting concerns implemented per handler can diverge. Repeated policy plus observed drift or
  ordering/security risk is the signal, and
  consider a shared chain stage or collaborator before a base controller: Java's single
  class inheritance makes independently varying base-class policies awkward to combine.
- **Choose the chain stage by what it must see.** Ordinary Servlet filters run before MVC
  handler selection. Interceptors see the selected handler but are not a sufficient security
  boundary: Spring warns of path-matching mismatches. Use the security chain and enabled
  method security; test uncovered routes and alternate dispatches.
- The framework's model map is a presentation concern. Putting entities in it couples the
  template to entity properties and can trigger lazy loading during rendering
  (`orm-behavioral-patterns`).
- Validation splits in two and both halves are needed: **syntactic** (required, format,
  range) belongs at the boundary, on the request type; **semantic** (this customer may not
  order this product) belongs in the domain, where it can be enforced regardless of the
  caller.
- One deliberate error contract across the application's HTTP boundaries. RFC 9457 problem details give a standard
  target (`rpc-and-api-contracts`).
- **Application Controller is the least-known pattern here and the most useful** where it
  applies: multi-step flows, approval chains, state machines. Its value is that the flow
  becomes a testable object rather than a set of redirects spread over handlers.
- Do not map classical page-flow patterns onto an HTTP API by analogy. An API may expose resources,
  commands, workflows and hypermedia; Remote Facade is useful when network granularity requires it,
  not a synonym for every REST endpoint
  (`remote-facade-and-dto`).
- Handler tests cover binding, validation, status codes and error shape with application
  doubles where useful. Separate integration tests may legitimately include a database to
  verify transaction, authorization or serialization behavior (`architecture-testing`).

Return the observed responsibility/ordering issue, the proposed placement and its evidence,
and the focused checks performed or still needed. Missing configuration makes claims about
filter coverage, authorization and transaction scope conditional; inspect it before diagnosing.

## References

- [Page Controller versus Front Controller](references/page-vs-front-controller.md) — both
  patterns in a modern stack, exactly which shared concern belongs at which stage of the
  chain (filter, interceptor, argument resolver, advice) with the ordering that matters, the
  base-controller anti-pattern, and how the same reasoning applies to a message consumer or
  a scheduled job. Read when placing a cross-cutting concern or reviewing a controller.
- [Application Controller](references/application-controller.md) — flow logic extracted from
  handlers: a state machine over an application process, where the flow state lives, how it
  is tested without HTTP, and when a flow abstraction is overkill. Read when a wizard,
  approval chain or multi-step process is being built or has become unmanageable.

