Skip to content

Non-Deterministic and Priority Sorting of Middleware and Routes #6

@psenger

Description

@psenger

This document outlines a critical feature request to implement deterministic and predictive, convention-based ordering for routes and middleware in express-auto-router. This addresses a fundamental routing conflict issue and provides users with explicit control over route registration order.

Problem Statement

Current Issue: Route Conflicts

The current implementation has a critical flaw where route registration order depends on filesystem directory order (typically alphabetical), leading to non-deterministic behavior and route conflicts.

Example Conflict:

routes/
├── users/
│   ├── [id]/index.js       # Registers: /users/:id/
│   └── all/index.js        # Registers: /users/all/

Problem: If [id] is processed before all (bracket comes before 'a' in ASCII), Express registers /users/:id/ first, causing it to intercept requests to /users/all/ because the dynamic parameter :id matches "all". This is a bad API design, however the application does not provide a mechanism to overcome the desired result.

Current Issue: Middleware Function Order Conflict

The current implementation has no mechanism to control the execution order of middleware functions as they are merged and inherited through the directory tree hierarchy. When middleware from parent directories combines with middleware from child directories, the resulting execution order is non-deterministic.

Example Conflict:

// routes/_middleware.js (parent)
module.exports = (options) => {
  return [fn-1, fn-2]  // Parent middleware
}

// routes/users/_middleware.js (child)
module.exports = (options) => {
  return [fn-3, fn-4]  // Child middleware
}

// routes/users/admin/_middleware.js (grandchild)
module.exports = (options) => {
  return [fn-5]  // Grandchild middleware
}

Problem: When accessing /users/admin/, middleware functions are merged from all levels, but the merging and ordering logic is non-deterministic:

  • Current execution: Could be [fn-1, fn-2, fn-3, fn-4, fn-5] OR [fn-3, fn-4, fn-1, fn-2, fn-5] OR other combinations
  • Desired execution: Predictable order like [fn-1(priority:5), fn-3(priority:10), fn-2(priority:20), fn-5(priority:30), fn-4(priority:40)]
  • Result: CORS, auth, and other middleware execute in wrong order causing failures

Inheritance Tree Problem:

  • Functions from / merge with functions from /users/
  • Combined result merges with functions from /users/admin/
  • No control over how functions are ordered during merging process
  • No way to specify that a parent function should execute before/after child functions

Current Limitations

  1. Non-deterministic Route Order: Routes register in filesystem order
  2. No User Control: Developers cannot explicitly control route priority
  3. Silent Failures: Conflicts go undetected until runtime
  4. Middleware Ordering: Similar issues exist with middleware execution order
  5. Scalability Issues: Complex routing hierarchies become unpredictable

Real-World Impact

  • Production Bugs: Routes may work in development but fail in production due to different filesystem ordering
  • Maintenance Nightmares: Debugging route conflicts is extremely difficult
  • API Reliability: Users can't guarantee their API endpoints will work as expected
  • Team Confusion: Different developers may experience different route behavior

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions