The facade service pattern helps simplify complex code by hiding details behind a simple interface. It makes your Angular app easier to use and maintain.
Facade service pattern in Angular
Start learning this pattern below
Jump into concepts and practice - no test required
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class FacadeService { constructor(private serviceA: ServiceA, private serviceB: ServiceB) {} getData() { // combine or simplify calls return this.serviceA.getDataA(); } saveData(data: any) { this.serviceB.saveDataB(data); } }
The facade service is an Angular service decorated with @Injectable.
It uses dependency injection to get other services and exposes simpler methods.
export class UserFacade { constructor(private userService: UserService) {} getUser() { return this.userService.fetchUser(); } }
export class ProductFacade { constructor(private productService: ProductService, private cartService: CartService) {} getProducts() { return this.productService.getAll(); } addToCart(productId: string) { this.cartService.add(productId); } }
This example shows a facade service that hides two services: one for data and one for logging. The component uses only the facade to get data and log actions.
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class DataService { getData() { return 'Data from DataService'; } } @Injectable({ providedIn: 'root' }) export class LoggerService { log(message: string) { console.log('Log:', message); } } @Injectable({ providedIn: 'root' }) export class FacadeService { constructor(private dataService: DataService, private loggerService: LoggerService) {} fetchData() { this.loggerService.log('Fetching data'); return this.dataService.getData(); } } // Usage in a component import { Component } from '@angular/core'; import { FacadeService } from './facade.service'; @Component({ selector: 'app-root', template: `<h1>{{ data }}</h1>` }) export class AppComponent { data = ''; constructor(private facade: FacadeService) { this.data = this.facade.fetchData(); } }
Facade services keep your components simple and focused on displaying data.
They help reduce repeated code by centralizing logic.
Use facades to improve testability by mocking one service instead of many.
The facade service pattern hides complex service logic behind simple methods.
It makes Angular components cleaner and easier to maintain.
Use it to combine multiple services and centralize data handling.
Practice
What is the main purpose of using a Facade Service in Angular?
Solution
Step 1: Understand the role of Facade Service
A Facade Service acts as a simple interface hiding complex logic from components.Step 2: Identify the benefit in Angular components
This pattern keeps components clean and easier to maintain by centralizing service calls.Final Answer:
To simplify component code by hiding complex service logic behind simple methods -> Option CQuick Check:
Facade Service purpose = Simplify logic [OK]
- Thinking Facade replaces Angular modules
- Believing Facade manipulates DOM directly
- Assuming Facade creates multiple service instances
Which of the following is the correct way to inject a facade service MyFacadeService into an Angular component constructor?
Solution
Step 1: Recall Angular dependency injection syntax
Angular injects services via constructor parameters with access modifiers and type annotations.Step 2: Match correct syntax
constructor(private myFacadeService: MyFacadeService) {} usesprivateand typeMyFacadeService, which is correct.Final Answer:
constructor(private myFacadeService: MyFacadeService) {} -> Option AQuick Check:
Inject service with private + type [OK]
- Omitting access modifier (private/public)
- Using new keyword inside constructor parameters
- Assigning service without type annotation
Given this facade service method:
getUserName(): Observable<string> {
return this.userService.getUser().pipe(
map(user => user.name)
);
}What will the component receive when subscribing to getUserName()?
Solution
Step 1: Analyze the facade method return type
The method returns an Observable<string> by mapping the user object to user.name.Step 2: Understand what subscribing receives
Subscribing to this Observable emits the user's name string asynchronously.Final Answer:
An observable emitting the user's name as a string -> Option DQuick Check:
Facade returns Observable of user name [OK]
- Confusing Observable with Promise
- Expecting synchronous value instead of Observable
- Assuming entire user object is emitted
Identify the error in this facade service method:
fetchData() {
this.apiService.getData().subscribe(data => {
this.data = data;
});
return this.data;
}Solution
Step 1: Understand asynchronous subscription
The subscribe callback runs later, sothis.datais not set immediately.Step 2: Identify return timing issue
The method returnsthis.dataimmediately, likely undefined before data arrives.Final Answer:
Returns data before subscription completes, causing undefined result -> Option BQuick Check:
Async subscribe returns undefined early [OK]
- Returning data before async call finishes
- Thinking arrow functions are invalid in subscribe
- Believing subscription must be in component only
You want to create a facade service that combines data from UserService and SettingsService and exposes a single observable userSettings$. Which approach correctly implements this?
class UserSettingsFacade {
userSettings$: Observable<UserSettings>;
constructor(private userService: UserService, private settingsService: SettingsService) {
// Fill in here
}
}Solution
Step 1: Combine multiple observables correctly
UsecombineLatestto emit latest values from both observables together.Step 2: Map combined values into single object
Usemapoperator to create an object with user and settings properties.Final Answer:
this.userSettings$ = combineLatest([this.userService.getUser(), this.settingsService.getSettings()]).pipe(map(([user, settings]) => ({ user, settings }))); -> Option AQuick Check:
Use combineLatest + map to merge observables [OK]
- Using + operator to add observables
- Mapping one observable to another observable instead of values
- Using forkJoin which waits for all to complete once
