Skip to main content

APIs and Services Without Blurry Boundaries

How to design boundaries between routes, services, and responsibilities without turning the system into a pile of hidden coupling.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

Track

System Design Interviews - From Basics to Advanced

Step 4 / 19

The problem

Many APIs become confusing for a simple reason: nobody made responsibility clear.

Then the code starts to look familiar:

  • the controller validates input, applies rules, calls the database, and shapes the response
  • the service knows about HTTP status codes and headers
  • the repository decides business behavior
  • some helper file quietly owns an important part of the flow

That can look fine for a while. The problem shows up when the first real change arrives. A rule changes, a second entry point appears, or an incident forces the team to trace the flow. Then everyone asks the same question:

where is this decision actually supposed to live?

Mental model

A good boundary reduces doubt.

When another engineer opens the code, it should be easy to answer:

  • who receives external input
  • who validates format, permissions, and contract
  • who applies the business rule
  • who talks to the database or an external provider
  • who turns the result into an API response

You do not need ceremonial architecture to get this right. You just need to separate a few kinds of responsibility that often get mixed together:

  1. transport concerns like HTTP, status codes, headers, and serialization
  2. business logic and decision-making
  3. infrastructure concerns like databases, queues, caches, and providers
  4. response shaping

A simple rule helps a lot:

If the same file is making business decisions and also knows transport or persistence details, the boundary is already getting blurry.

Breaking it down

A practical split often looks like this:

  1. the route receives the request, handles basic validation and auth, and calls the flow
  2. the service or use case coordinates the business rule
  3. repositories or clients talk to the database, queue, or external service
  4. the entry layer turns the result into the final response

This is not a religion. It is just a way to stop one file from doing everything.

Another good question is:

If the rule changes tomorrow, where would I expect to edit first?

If the honest answer is “maybe three controllers, two helpers, and one repository,” the boundary is weak.

Simple example

Imagine an endpoint for creating an order.

A blurry version might do all of this in the controller:

  • validate the cart
  • check stock
  • calculate shipping
  • decide the initial status
  • save to the database
  • send an email

Now imagine the same flow with better boundaries:

  • the route validates input and auth
  • the createOrder service decides stock, total, shipping, and status
  • the repository persists the order
  • an event or queue handles follow-up notifications

The gain is not aesthetic. It is operational.

When pricing changes, you know where to go. When the database changes, the core rule does not need to learn SQL details. When email fails, the controller does not need to become a giant try/catch block that knows the whole flow.

Common mistakes

  • spreading business rules across controller, service, and repository with no real pattern
  • adding layers that do not have clearly different responsibilities
  • coupling API responses too tightly to internal table structure
  • turning the controller into a service with a different filename
  • debating folder structure instead of responsibility

There is an opposite mistake too: overdoing the separation.

Some endpoints are simple. They do not need five objects, three interfaces, and two factories. The goal is not to collect architectural layers. The goal is to avoid dangerous mixing.

How a senior thinks

A stronger engineer usually looks at maintenance and change before they look at architectural purity.

The reasoning is usually something like this:

“I want the important rule to live in a predictable place, and I do not want HTTP, database, or provider details leaking into that decision.”

That helps in a few ways:

  • rule changes create less cascade
  • testing gets easier at the right level
  • the same business flow is easier to reuse outside the API

In real work, that matters more than a pretty diagram. In interviews, it shows that you are designing boundaries to reduce maintenance cost, not to look sophisticated.

What the interviewer wants to see

When the topic is API and service boundaries, the interviewer usually wants to see whether you:

  • separate responsibility with a reason
  • know where business rules should live
  • avoid coupling HTTP, business logic, and persistence
  • think about future change, not just first delivery

A strong answer often sounds like this:

“The controller receives and validates the request. The main rule lives in the business flow. Database and provider concerns stay behind a layer I can change without moving the core decision.”

That sends the right signal: you are thinking about boundaries as a risk-reduction tool.

A good API is not the one with the most layers. It is the one that makes it obvious where each decision lives.

Quick summary

What to keep in your head

Practice checklist

Use this when you answer

You finished this article

Part of the track: System Design Interviews - From Basics to Advanced (4/19)

Next article RAG vs Fine-Tuning Without a False Binary Previous article Scalability and Bottlenecks

Keep exploring

Related articles