Building a Scalable Express Backend for Wooster
Planning the architecture
After getting my database schema sorted and teaching Wooster to generate coherent travel plans, it was time to build the API. But before writing a single endpoint, I wanted to get the architecture right.
Starting with Structure
While it's tempting to throw everything into a single server.ts
file when prototyping (I've been burned by that before), I decided to be a responsible developer and set up a proper MVC structure from the start:
src/
├── controllers/ # Request handlers by resource
├── models/ # Database client and models
├── services/ # Business logic and external services
├── routes/ # Route definitions
├── types/ # TypeScript interfaces and types
├── utils/ # Shared utilities
├── middleware/ # Express middleware
└── config/ # Configuration and constants
This might seem like overkill for an MVP, but past-me has burned present-me too many times with "I'll restructure it later."
The MVP Endpoints
For the initial version, I kept it simple:
But the real magic wasn't in the routes - it was in how I handled them. Take adding a destination, for example:
Separation of Concerns in Action
Instead of stuffing everything into route handlers, each piece had its place:
The controller only handled the HTTP layer - all the business logic lived in services:
Evolution: Adding User Features
Once I actually implemented auth (post-MVP) I realised in my testing that we would also need a separate saved destinations table. This meant adding new endpoints:
(The authentication story deserves its own article - let's just say Supabase made it much less painful than it could have been!)
What I Actually Learned
- Start with good architecture - moving files is harder than creating them
- Controllers should be thin - business logic belongs in services
- Type everything from the start - TypeScript is your friend
- Error handling deserves attention early - users don't appreciate raw error stacks
- Organize by feature, not function - keeps related code together
- CORS configuration is always trickier than you expect
- Log everything in development
Next up in Part 5: "Structuring the Front End: Building Wooster's User Interface", where I walk you through feature-driven component architecture.