Dependency injection helps you organize your code by giving parts what they need instead of making them find it themselves. This makes your app easier to manage and test.
Dependency injection in Express
function createRouter(dependency) {
const router = require('express').Router();
router.get('/', (req, res) => {
const data = dependency.getData();
res.send(data);
});
return router;
}
const myDependency = {
getData: () => 'Hello from dependency!'
};
const app = require('express')();
app.use('/path', createRouter(myDependency));You create functions that accept dependencies as parameters.
Then you pass the actual dependencies when you use those functions.
function createLogger() {
return {
log: (msg) => console.log('LOG:', msg)
};
}
function createRouter(logger) {
const router = require('express').Router();
router.get('/', (req, res) => {
logger.log('Route accessed');
res.send('Check console for log');
});
return router;
}
const logger = createLogger();
const app = require('express')();
app.use('/', createRouter(logger));function createUserService(db) {
return {
getUser: (id) => db.findUserById(id)
};
}
const fakeDb = {
findUserById: (id) => ({ id, name: 'Test User' })
};
const userService = createUserService(fakeDb);
const app = require('express')();
app.get('/user/:id', (req, res) => {
const user = userService.getUser(req.params.id);
res.json(user);
});This program creates a message service and injects it into a router. The router uses the service to send a message when you visit /message.
const express = require('express'); // Dependency: simple message service function createMessageService() { return { getMessage: () => 'Hello from the message service!' }; } // Router factory that injects the message service function createMessageRouter(messageService) { const router = express.Router(); router.get('/', (req, res) => { const message = messageService.getMessage(); res.send(message); }); return router; } const app = express(); const messageService = createMessageService(); app.use('/message', createMessageRouter(messageService)); app.listen(3000, () => { console.log('Server running on http://localhost:3000/message'); });
Dependency injection helps keep your code clean and easy to test.
Always inject dependencies instead of requiring them inside modules to improve flexibility.
Use this pattern especially when your app grows bigger and has many parts.
Dependency injection means giving parts of your app what they need instead of making them find it.
It helps keep code organized, testable, and flexible.
In Express, you can inject dependencies by passing them to router or service factory functions.
Practice
Solution
Step 1: Understand dependency injection concept
Dependency injection means giving parts of your app what they need instead of making them find it themselves.Step 2: Identify the purpose in Express
In Express, this helps keep code organized and flexible by passing dependencies explicitly.Final Answer:
To provide parts of the app with the resources they need without hardcoding them -> Option AQuick Check:
Dependency injection = Provide needed resources [OK]
- Confusing dependency injection with caching
- Thinking it auto-generates routes
- Mixing it with error handling
Solution
Step 1: Check how to pass dependencies in Express
Express.Router() does not accept parameters directly, so passing service as argument is invalid.Step 2: Use a factory function to inject service
Creating a function that takes service and returns a router with service attached is the correct pattern.Final Answer:
function createRouter(service) { const router = express.Router(); router.service = service; return router; } -> Option CQuick Check:
Inject by factory function = function createRouter(service) { const router = express.Router(); router.service = service; return router; } [OK]
- Passing service directly to express.Router()
- Calling service as a middleware incorrectly
- Assigning service without a factory function
function createService() {
return { getName: () => 'MyService' };
}
function createRouter(service) {
const router = require('express').Router();
router.get('/name', (req, res) => {
res.send(service.getName());
});
return router;
}
const service = createService();
const router = createRouter(service);
// What happens when a GET request is made to '/name'?Solution
Step 1: Analyze service creation
The createService function returns an object with getName method returning 'MyService'.Step 2: Analyze router handler
The router uses the injected service and calls getName to send the response on '/name' route.Final Answer:
The response will be 'MyService' -> Option DQuick Check:
Injected service method returns 'MyService' [OK]
- Assuming service is undefined inside handler
- Thinking service causes runtime error
- Confusing middleware with service injection
function createRouter(service) {
const router = require('express').Router();
router.get('/data', (req, res) => {
res.send(service.getData());
});
return router;
}
const router = createRouter();
What is the main issue here?Solution
Step 1: Check function call for createRouter
The createRouter function expects a service argument, but none is passed, so service is undefined.Step 2: Understand impact on route handler
Calling service.getData() will cause a runtime error because service is undefined.Final Answer:
The router is missing the service argument, causing service to be undefined -> Option AQuick Check:
Missing dependency argument = undefined service [OK]
- Thinking express() should replace express.Router() here
- Confusing method definition with dependency injection
- Assuming route path is invalid
Solution
Step 1: Understand dependency injection best practice
Injecting dependencies via factory functions keeps routers independent and testable.Step 2: Evaluate options for injecting database client
Factory functions allow passing the client explicitly to each router, avoiding globals and repeated initialization.Final Answer:
Create a factory function for each router that accepts the database client and returns a configured router -> Option BQuick Check:
Factory functions for injection = Create a factory function for each router that accepts the database client and returns a configured router [OK]
- Using global variables which reduce testability
- Attaching client to app instance instead of injecting
- Initializing client on every request causing overhead
Ready to prove it?
Pass the test and this pattern moves unknown
