Layering a backend service

System design Junior Python 3.13+ PostgreSQL 17+ Reviewed By Best Latest Apps

Pick the fix

Where should the rule 'an order can't be refunded after 30 days' live?

Options
Hint 1 of 1

Which layer do all entry points share?

Choose an answer, then open Show answer below to check it.

Sort 12 responsibilities into API, Service, Data and Infra lanes, then check each placement with a one-line reason.
Text version

API:

  • Parse the JSON body and reject unknown fields: Input validation is the HTTP boundary's job, before any rule runs.
  • Return 404 vs 409 for an error: Mapping outcomes to status codes is HTTP-specific, so it stays at the edge.
  • Check the caller's token and scopes: Authentication happens before the request reaches business code.

Service:

  • Rule: refunds only within 30 days: A business rule every entry point must obey, so it lives in the domain layer.
  • Reserve stock and create the order as one unit: The service defines the unit of work and opens the transaction around it.
  • Decide which email to send after checkout: Choosing the next business step is orchestration, not HTTP or SQL.

Data:

  • SELECT the order with its items in one query: Queries live in repositories so services never see SQL.
  • Map a database row to an Order object: Row-to-object mapping is the data layer's boundary work.
  • Read-through cache for product lookups: Caching is a detail of how data is fetched; services just ask for products.

Infra:

  • Ship logs and traces to the collector: Observability plumbing is shared infrastructure, not business logic.
  • Load DATABASE_URL at startup: Configuration is supplied by the environment the service runs in.
  • Drain requests on SIGTERM: Process lifecycle belongs to the runtime and deployment platform.
Show answer

Answer: A In the service (domain) layer

Correct. It's a business rule every entry point must respect.

Business rules belong where every caller has to pass through: the service layer. HTTP handlers, queue consumers and admin scripts all call it, so the 30-day rule can't be bypassed.

Why not the others?
  • B In the HTTP handler. A queue consumer or admin tool would bypass it.
  • C In the SQL query only. Hidden, hard to test, and the error message is lost.
  • D In the load balancer. Infrastructure doesn't know about refunds.

30-second answer

A common split is four layers. The API layer handles HTTP: parsing, validation, auth, status codes. The service (domain) layer holds business rules and orchestrates work, with no HTTP or SQL in it. The data layer owns queries, transactions and caches behind repository interfaces. Infrastructure covers deployment, queues, config and observability plumbing. Dependencies point inward, so rules can be tested without a web server or database.

Practise saying it · 30 s. No recording, just a timer

Layer a service.

Say your answer out loud, then check which of these points you covered:

  • API: HTTP, auth, validation
  • Service: rules
  • Data: queries, transactions
  • Infra: plumbing
  • Dependencies inward

Deep dive

Keep transactions at the service layer, where the business operation is defined.

Map database rows to domain objects at the data layer boundary.

Don't let ORM objects leak into API responses.

Small services can merge layers; the dependency direction still matters.

Common mistakes

  • Business rules in HTTP handlers.
  • SQL scattered through services.
  • Returning ORM objects directly as JSON.

Senior take & follow-ups

Name the layers with examples, the dependency rule, and where transactions sit.

Follow-up questions

Think of your answer first, then open the hint.

  1. Where do transactions belong?

    Show hint

    Around the service-layer operation that defines the unit of work.

  2. Why point dependencies inward?

    Show hint

    So rules don't depend on frameworks and can be unit-tested.

Suggest a fix if something here is wrong or out of date.