DEV Community

Ace-2504
Ace-2504

Posted on

How Structured Thinking Fixed REST API Design

Executive Summary

While building the backend for Ace Rentals, I realized that my authorization logic, although functionally correct, felt increasingly fragile. Ownership checks were scattered across multiple routes, duplicated in several places, and easy to forget when adding new endpoints. Over time, this made the system harder to reason about and increased the risk of subtle security gaps.

Rather than continuing with incremental fixes, I stepped back and redesigned authorization as a system-level concern using centralized middleware. This article explains how I identified the issue, how I reasoned about the redesign, how it was implemented, and what improved as a result.

Previous Authorization Approach

Authorization checks were implemented directly inside individual route handlers. Each protected endpoint contained its own logic to verify whether the current user was allowed to perform the requested action.

While this approach worked initially, it introduced several challenges as the application grew:

  • The same ownership logic was copied across multiple routes
  • Route handlers mixed business logic with authorization concerns
  • Adding new endpoints required manual checks, increasing the chance of mistakes

The system did not fail outright, but correctness increasingly depended on careful and repetitive implementation.

Identifying the Design Issue

The problem was not a missing check or a faulty condition—it was a structural issue. Authorization was treated as an implementation detail instead of a rule enforced consistently by the architecture.

This meant security relied on developer memory rather than system guarantees. As the number of routes increased, so did the effort required to maintain consistency and confidence in the design.

Design Analysis and Decision-Making

To avoid patching individual routes, I analyzed the problem at a design level.

  • I used MECE-style analysis to verify whether authorization was applied consistently across all relevant routes. This exposed gaps and overlap in enforcement.
  • I compared alternative approaches and found that centralized middleware offered the best balance between reuse, clarity, and maintainability.
  • I set clear constraints for the refactor—no change in behavior, minimal surface area, and focused scope—to avoid unnecessary complexity.

This structured approach helped ensure the redesign addressed the root cause rather than its symptoms.

Authorization Redesign and Implementation

Authorization was elevated to a system-level concern and implemented through middleware:

  • Ownership checks were consolidated into a single, reusable middleware function
  • API endpoints were reorganized around resources rather than actions, improving clarity
  • Authorization was enforced early in the request pipeline, before any business logic executed

With this setup, routes automatically inherit authorization rules. Developers no longer need to remember to reapply checks when adding or modifying endpoints.

Observed Impact of the Redesign

The redesign produced clear and measurable improvements:

  • Authorization logic now exists in one place instead of being duplicated
  • All protected routes enforce authorization consistently by default
  • Maintenance effort and regression risk were significantly reduced
  • Resource relationships are clearer through resource-based routing
  • Route handlers are simpler and focus only on business logic

A qualitative review showed that core domain logic is stable. Remaining risk is isolated to shared authorization middleware, where it is explicit, visible, and easier to reason about.

Key Learning

Repeated logic is often a signal of a deeper design issue. Treating security as a structural concern—rather than a manual step—leads to systems that are easier to maintain, extend, and trust over time.

Design Decisions and Learnings

This article provides a high-level summary of the decisions and outcomes from redesigning authorization in Ace Rentals.

For a deeper look into my learning experience—including diagrams, structured reasoning, trade-offs, and implementation details—you can read the full write-up here:

👉 https://ace-2504.github.io/api-design-blog/

The full version documents the complete thought process and lessons learned while designing and refactoring the system.

Top comments (2)

Collapse
 
sleewoo profile image
Slee Woo

Yeah, repetitive pattern is tedious on dev and dangerous in production.
Partially solved by using imports/wiring manually.
But the real solution was Middlewrappers

Collapse
 
ace2504 profile image
Ace-2504

Agreed. Manual wiring reduces repetition but still depends on developer discipline, which is risky at scale. Moving authorization into middleware (“middlewrappers”) makes enforcement structural—part of the request flow—rather than something developers have to remember.