What if changing your database didn't mean rewriting half your app?
Why Repository pattern for data access in Express? - Purpose & Use Cases
Imagine building an app where you write raw database queries everywhere in your Express routes. Every time you want to change how data is fetched or saved, you must hunt through all your files to update those queries.
Scattering database code all over makes your app hard to maintain and test. If the database changes, you risk breaking many parts. It's slow to add features or fix bugs because you repeat similar code everywhere.
The Repository pattern creates a single place to handle all data access. Your routes just ask the repository for data, so you can change database details inside the repository without touching the rest of your app.
app.get('/users', (req, res) => { db.query('SELECT * FROM users', (err, results) => { res.send(results); }); });
class UserRepository { getAll() { return db.query('SELECT * FROM users'); } } const userRepository = new UserRepository(); app.get('/users', async (req, res) => { const users = await userRepository.getAll(); res.send(users); });
This pattern lets you swap databases, add caching, or change queries easily without rewriting your whole app.
When your app grows and you switch from a simple JSON file to a real database, the Repository pattern lets you make that change smoothly without breaking your routes.
Manual data access scattered in routes is hard to maintain.
Repository pattern centralizes data logic for easier updates.
It improves app flexibility, testing, and scalability.
Practice
Repository pattern in an Express app?Solution
Step 1: Understand the role of repository pattern
The repository pattern is designed to isolate data access logic from the rest of the application.Step 2: Identify the correct purpose in Express context
In Express apps, it helps keep business logic clean by moving database queries into repositories.Final Answer:
To separate data access logic from business logic -> Option DQuick Check:
Repository pattern = separate data access [OK]
- Confusing repository with routing or middleware
- Thinking it handles UI or styling
- Mixing it with authentication logic
Solution
Step 1: Identify ES6 class syntax
ES6 classes use theclasskeyword with methods inside without thefunctionkeyword.Step 2: Match the correct syntax
class UserRepository { getAll() { /* code */ } } correctly defines a class with a methodgetAll()using ES6 syntax.Final Answer:
class UserRepository { getAll() { /* code */ } } -> Option AQuick Check:
ES6 class syntax = class UserRepository { getAll() { /* code */ } } [OK]
- Using function keyword inside class methods
- Confusing arrow functions with class methods
- Using old object syntax instead of class
console.log(users) output?class UserRepository {
constructor() {
this.users = [{id:1, name:'Anna'}, {id:2, name:'Bob'}];
}
getAll() {
return this.users;
}
}
const repo = new UserRepository();
const users = repo.getAll();
console.log(users);Solution
Step 1: Understand the constructor initialization
The constructor setsthis.usersto an array of two user objects.Step 2: Check the getAll method return value
ThegetAll()method returnsthis.users, so calling it returns the array.Final Answer:
[{id:1, name:'Anna'}, {id:2, name:'Bob'}] -> Option AQuick Check:
getAll returns users array [OK]
- Assuming getAll returns undefined or empty
- Confusing method call with property access
- Expecting an error due to missing binding
class ProductRepository {
constructor() {
this.products = [];
}
add(product) {
this.products.push(product);
}
getAll() {
return products;
}
}Solution
Step 1: Check variable usage in getAll method
The method returnsproductsbut this variable is not defined in the method scope.Step 2: Correct usage of instance variable
It should returnthis.productsto access the class property.Final Answer:
Using undefined variable 'products' instead of 'this.products' -> Option BQuick Check:
Use this.products to access class property [OK]
- Forgetting 'this.' prefix for class properties
- Assuming variables are global inside class methods
- Ignoring constructor initialization
findByEmail(email) for users. Which approach correctly implements this in Express?Solution
Step 1: Understand class inheritance in ES6
Extending a base class usesextendskeyword andsuper()if constructor is needed.Step 2: Check method implementation accessing instance data
class UserRepository extends BaseRepository { findByEmail(email) { return this.data.find(u => u.email === email); } } correctly extendsBaseRepositoryand usesthis.datato find user by email.Final Answer:
class UserRepository extends BaseRepository { findByEmail(email) { return this.data.find(u => u.email === email); } } -> Option CQuick Check:
Extend base class and add method using this.data [OK]
- Not using 'extends' for inheritance
- Accessing base class data incorrectly
- Overwriting prototype without proper inheritance
Ready to prove it?
Pass the test and this pattern moves unknown
