Implement an HTTP Router That Resolves Handlers for Paths with Named Parameters

Read the full interview experience this question came from →

Quick Overview

Implement an HTTP router that registers handlers for path patterns, some with named parameters and some without, and looks up the handler and parameter values for a request path. It tests data structure choice, precedence between fixed and parameterized segments, conflict handling and lookup complexity.

Implement an HTTP Router That Resolves Handlers for Paths with Named Parameters

Company: Google

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

Implement an HTTP router: the component that maps the path of an incoming request to the handler registered for it. It supports two operations: - `register(pattern, handler)` stores a handler for a path pattern. - `get(path)` finds the handler whose pattern matches a concrete request path and returns it together with the values of the pattern's parameters. Some patterns contain parameters and some do not. Assume a parameter is written as `:name` and stands for exactly one path segment: `/users/:id/profile` matches `/users/42/profile` with `id = "42"`, while `/about` matches only `/about`. You do not need to write the code that splits a path into segments; assume this helper already exists: ```python def split_path(path: str) -> list[str]: """"/users/42/profile" -> ["users", "42", "profile"]; "/" -> []""" ``` A possible interface (adjust it as you clarify): ```python from typing import Callable Handler = Callable[..., object] class Router: def register(self, pattern: str, handler: Handler) -> None: ... def get(self, path: str) -> tuple[Handler, dict[str, str]] | None: ... ``` ```hint Do not compare against every route Many patterns begin with the same segments. Look for a structure in which a lookup walks the request path once, segment by segment, instead of testing it against each registered pattern. ``` ```hint Where the names live Decide where a parameter's name is stored so that a lookup can report the value it matched, and what a lookup should do when a fixed segment and a parameter could both match at the same position. ``` ### Constraints and Clarifications - The parameter syntax (`:name`, occupying one whole segment) is an assumption; confirm it. - Splitting is handled by `split_path`, and the query string has already been removed from the request path. ### Clarifying Questions - If both a fixed pattern and a parameterized pattern match a request, such as `/users/me` and `/users/:id` for the path `/users/me`, which one wins? - If a fixed branch matches the first segments but has no route for the rest, should the router fall back to a parameterized pattern? For example, with `/users/me/settings` and `/users/:id/posts` registered, what should `/users/me/posts` return? - What should registering the same pattern twice do, and what about two patterns that differ only in parameter names, such as `/users/:id` and `/users/:user_id`? - Is the HTTP method part of the route? Are there wildcards that match the rest of the path? - Are trailing slashes significant, and are paths case-sensitive? - What should `get` return when no pattern matches? ### What a Strong Answer Covers - Settles the parameter syntax, the precedence between fixed and parameter segments, duplicate registrations and the no-match result before coding - A structure keyed by path segments that shares common prefixes, with a clear place for each handler and its parameter names - A lookup that returns the right handler and parameter values under the chosen precedence, including when a preferred branch dead-ends - Time and memory complexity in terms of path length and the number of registered routes - Tests for the root path, overlapping patterns, conflicting registrations and misses ### Follow-up Questions - The same path can now have different handlers for GET and POST, and a path that exists under another method must be distinguishable from one that does not exist. What changes? - Add a catch-all parameter that matches the rest of the path, such as `/static/*filepath`. Where does it rank against the other kinds of segment? - What is the worst-case cost of one `get` call in your design, and which sets of registered patterns trigger it? - Routes are registered at startup and then read by many request threads. What, if anything, needs locking, and what changes if routes can be added while traffic is being served?

Overview: Implement an HTTP router that registers handlers for path patterns, some with named parameters and some without, and looks up the handler and parameter values for a request path. It tests data structure choice, precedence between fixed and parameterized segments, conflict handling and lookup complexity.

Read the full Google Software Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/Google
Google logo
Google
Oct 16, 2026
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
0
0

Implement an HTTP router: the component that maps the path of an incoming request to the handler registered for it. It supports two operations:

  • register(pattern, handler) stores a handler for a path pattern.
  • get(path) finds the handler whose pattern matches a concrete request path and returns it together with the values of the pattern's parameters.

Some patterns contain parameters and some do not. Assume a parameter is written as :name and stands for exactly one path segment: /users/:id/profile matches /users/42/profile with id = "42", while /about matches only /about.

You do not need to write the code that splits a path into segments; assume this helper already exists:

def split_path(path: str) -> list[str]:
    """"/users/42/profile" -> ["users", "42", "profile"]; "/" -> []"""

A possible interface (adjust it as you clarify):

from typing import Callable

Handler = Callable[..., object]


class Router:
    def register(self, pattern: str, handler: Handler) -> None: ...
    def get(self, path: str) -> tuple[Handler, dict[str, str]] | None: ...

Constraints and Clarifications

  • The parameter syntax ( :name , occupying one whole segment) is an assumption; confirm it.
  • Splitting is handled by split_path , and the query string has already been removed from the request path.

Clarifying Questions Guidance

  • If both a fixed pattern and a parameterized pattern match a request, such as /users/me and /users/:id for the path /users/me , which one wins?
  • If a fixed branch matches the first segments but has no route for the rest, should the router fall back to a parameterized pattern? For example, with /users/me/settings and /users/:id/posts registered, what should /users/me/posts return?
  • What should registering the same pattern twice do, and what about two patterns that differ only in parameter names, such as /users/:id and /users/:user_id ?
  • Is the HTTP method part of the route? Are there wildcards that match the rest of the path?
  • Are trailing slashes significant, and are paths case-sensitive?
  • What should get return when no pattern matches?

What a Strong Answer Covers Guidance

  • Settles the parameter syntax, the precedence between fixed and parameter segments, duplicate registrations and the no-match result before coding
  • A structure keyed by path segments that shares common prefixes, with a clear place for each handler and its parameter names
  • A lookup that returns the right handler and parameter values under the chosen precedence, including when a preferred branch dead-ends
  • Time and memory complexity in terms of path length and the number of registered routes
  • Tests for the root path, overlapping patterns, conflicting registrations and misses

Follow-up Questions Guidance

  • The same path can now have different handlers for GET and POST, and a path that exists under another method must be distinguishable from one that does not exist. What changes?
  • Add a catch-all parameter that matches the rest of the path, such as /static/*filepath . Where does it rank against the other kinds of segment?
  • What is the worst-case cost of one get call in your design, and which sets of registered patterns trigger it?
  • Routes are registered at startup and then read by many request threads. What, if anything, needs locking, and what changes if routes can be added while traffic is being served?