Angular Services
Learn Angular Services in detail with Dependency Injection, service lifecycle, singleton services, CRUD examples, HTTP communication, state sharing, architecture diagrams, enterprise examples, best practices, and interview questions.
An Angular Service is a reusable TypeScript class that contains business logic, data access, API communication, shared state, and utility functions.
Services are one of the fundamental building blocks of Angular applications and work closely with Angular's Dependency Injection (DI) framework.
Instead of duplicating code across multiple components, Angular encourages placing reusable logic inside services.
Understanding Angular Services is one of the most frequently asked Angular interview topics for Senior Developers, Tech Leads, and Architects.
Table of Contents
- What are Angular Services?
- Why Services?
- Service Architecture
- Creating Services
- Dependency Injection
- Singleton Services
- HTTP Services
- State Sharing
- Feature Services
- Utility Services
- Service Communication
- Enterprise Example
- Best Practices
- Common Mistakes
- Top 10 Interview Questions
- Summary
What is an Angular Service?
An Angular Service is a plain TypeScript class decorated with:
@Injectable()
Services are responsible for:
- Business logic
- API communication
- Data transformation
- Authentication
- Shared state
- Utility functions
- Logging
- Caching
Angular Service Architecture
flowchart LR
Component
Component --> Injector
Injector --> Service
Service --> RESTAPI
RESTAPI --> Database
Database --> RESTAPI
RESTAPI --> Service
Service --> Component
Why Do We Need Services?
Without Services
Component A
↓
API Logic
↓
Business Logic
↓
Validation
↓
HTTP Calls
Component B
↓
Same Logic Again
Problems
- Duplicate code
- Difficult maintenance
- Tight coupling
- Hard testing
With Services
Component A
↓
UserService
↑
Component B
↑
Component C
Benefits
- Reusable code
- Separation of concerns
- Better testing
- Cleaner architecture
- Easier maintenance
Service Layer Architecture
flowchart TD
UI
UI --> Components
Components --> Services
Services --> HttpClient
HttpClient --> RESTAPI
RESTAPI --> Database
Creating a Service
Generate using Angular CLI
ng generate service services/user
or
ng g s services/user
Generated service
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
}
Why @Injectable?
The @Injectable() decorator tells Angular that the class participates in the Dependency Injection system.
@Injectable({
providedIn: 'root'
})
export class ProductService {}
Dependency Injection Flow
sequenceDiagram
participant Component
participant Injector
participant UserService
Component->>Injector: Request UserService
Injector->>UserService: Create or Reuse
UserService-->>Component: Service Instance
Using Services
Service
@Injectable({
providedIn: 'root'
})
export class UserService {
getUsers() {
return ['John', 'David', 'Venu'];
}
}
Component
@Component({
selector: 'app-home',
template: `
<div *ngFor="let user of users">
{{user}}
</div>
`
})
export class HomeComponent {
users: string[];
constructor(
private userService: UserService
) {
this.users = this.userService.getUsers();
}
}
Singleton Services
Services using
providedIn:'root'
are application-wide singleton services.
flowchart TD
RootInjector
RootInjector --> UserService
UserService --> ComponentA
UserService --> ComponentB
UserService --> ComponentC
One service instance is shared throughout the application.
Service Lifecycle
flowchart TD
ApplicationStart
ApplicationStart --> RootInjector
RootInjector --> ServiceRequest
ServiceRequest --> CreateService
CreateService --> ReuseService
ReuseService --> ApplicationEnd
Root services are typically created lazily the first time they are requested.
HTTP Services
Most Angular services communicate with REST APIs using HttpClient.
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EmployeeService {
private api =
'https://api.company.com/employees';
constructor(
private http: HttpClient
) {}
getEmployees(): Observable<Employee[]> {
return this.http.get<Employee[]>(this.api);
}
}
HTTP Communication Flow
flowchart LR
Component
Component --> EmployeeService
EmployeeService --> HttpClient
HttpClient --> RESTAPI
RESTAPI --> Database
Database --> RESTAPI
RESTAPI --> Component
CRUD Service Example
@Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(
private http: HttpClient
) {}
getProducts() {
return this.http.get('/api/products');
}
getProduct(id: number) {
return this.http.get(`/api/products/${id}`);
}
createProduct(product: Product) {
return this.http.post('/api/products', product);
}
updateProduct(
id: number,
product: Product
) {
return this.http.put(
`/api/products/${id}`,
product
);
}
deleteProduct(id: number) {
return this.http.delete(
`/api/products/${id}`
);
}
}
State Sharing Using Services
Services are commonly used to share state across components.
@Injectable({
providedIn: 'root'
})
export class ThemeService {
currentTheme = 'light';
setTheme(theme: string) {
this.currentTheme = theme;
}
}
Multiple components can access the same shared state.
Shared State Architecture
flowchart TD
HeaderComponent
HeaderComponent --> ThemeService
SidebarComponent --> ThemeService
DashboardComponent --> ThemeService
ThemeService --> SharedState
Using RxJS for Shared State
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserStateService {
private currentUser =
new BehaviorSubject<User | null>(null);
currentUser$ =
this.currentUser.asObservable();
setUser(user: User) {
this.currentUser.next(user);
}
}
Consumers
user$ =
this.userState.currentUser$;
This pattern enables reactive communication between unrelated components.
Service Types
| Service | Purpose |
|---|---|
| API Service | HTTP communication |
| Authentication Service | Login & Security |
| Product Service | Business logic |
| Payment Service | Transactions |
| Notification Service | Alerts |
| Logging Service | Logging |
| Utility Service | Helper functions |
| State Service | Shared application state |
Feature Services
Instead of creating one large service, split services by responsibility.
Good
UserService
OrderService
PaymentService
InventoryService
Avoid
ApplicationService
that contains every business operation.
Service Communication
flowchart TD
DashboardComponent
DashboardComponent --> AccountService
TransferComponent --> AccountService
AccountService --> HttpClient
HttpClient --> Backend
Services become the communication layer between the UI and backend.
Enterprise Banking Example
A banking application contains
- Authentication
- Accounts
- Loans
- Payments
- Notifications
- Audit
- Fraud Detection
Architecture
flowchart TD
BankDashboard
BankDashboard --> AuthService
BankDashboard --> AccountService
BankDashboard --> LoanService
BankDashboard --> PaymentService
BankDashboard --> NotificationService
PaymentService --> BankingAPI
LoanService --> BankingAPI
AuthService --> IdentityServer
NotificationService --> EmailGateway
Benefits
- Reusable business logic
- Centralized API communication
- Better scalability
- Easier testing
- Cleaner architecture
Performance Best Practices
| Practice | Benefit |
|---|---|
Use providedIn:'root' |
Singleton services |
| Keep services focused | Easier maintenance |
| Return Observables | Reactive programming |
Use HttpClient |
Angular HTTP features |
| Cache reusable data when appropriate | Fewer network requests |
| Avoid business logic in components | Cleaner UI |
Common Mistakes
Putting Business Logic Inside Components
Move reusable business logic into services.
Creating Huge Services
Break services into smaller feature-based services.
Using new
new UserService()
Always use Dependency Injection.
Storing Temporary Component State
Component-specific state generally belongs in the component unless it must be shared.
Subscribing Without Cleanup
For long-lived subscriptions, clean them up appropriately or use the async pipe when possible.
Best Practices
- Keep services focused.
- Prefer
providedIn: 'root'. - Use
HttpClientfor API communication. - Return
Observablevalues. - Share state through dedicated state services.
- Inject services instead of creating them manually.
- Write unit tests for business logic.
- Keep components thin and services rich.
Advantages
| Feature | Benefit |
|---|---|
| Reusability | Shared logic |
| Dependency Injection | Loose coupling |
| Singleton Support | Shared instances |
| Testability | Easy mocking |
| Scalability | Modular architecture |
| Separation of Concerns | Cleaner code |
Top 10 Angular Services Interview Questions
1. What is an Angular Service?
Answer
An Angular Service is an injectable TypeScript class used to encapsulate business logic, API communication, shared state, utilities, and reusable functionality.
2. Why should services be used?
Answer
Services eliminate duplicate code, improve maintainability, enable dependency injection, and separate business logic from presentation logic.
3. What is @Injectable()?
Answer
@Injectable() marks a class as participating in Angular's Dependency Injection system and allows Angular to create and inject it.
4. What is providedIn: 'root'?
Answer
It registers the service with the Root Environment Injector, creating an application-wide singleton that supports tree shaking.
5. How do components use services?
Answer
Components inject services using constructor injection or the inject() function.
6. Why should HttpClient be used inside services?
Answer
Services centralize API communication, keeping components focused on UI responsibilities while leveraging Angular's HTTP features.
7. Can services share data between components?
Answer
Yes.
Services commonly use RxJS subjects such as BehaviorSubject to share reactive state across components.
8. What types of services exist?
Answer
- API services
- Authentication services
- State management services
- Utility services
- Logging services
- Payment services
- Notification services
9. What are the best practices for Angular Services?
Answer
- Keep services focused.
- Prefer
providedIn: 'root'. - Use Dependency Injection.
- Return Observables.
- Use
HttpClient. - Keep business logic out of components.
- Write unit tests.
10. What are common mistakes when using services?
Answer
- Creating "God" services
- Using
newinstead of DI - Putting business logic in components
- Duplicating API calls
- Misusing singleton services for local UI state
- Ignoring subscription management
Interview Cheat Sheet
| Topic | Remember |
|---|---|
| Decorator | @Injectable() |
| Registration | providedIn:'root' |
| Injection | Constructor or inject() |
| API Calls | HttpClient |
| Reactive State | BehaviorSubject |
| Singleton | Root Injector |
| Shared Logic | Services |
| Components | Keep them thin |
| Testing | Mock services |
| Best Practice | One responsibility per service |
Summary
Angular Services are the backbone of application architecture. They encapsulate business logic, HTTP communication, shared state, and reusable functionality, allowing components to remain focused on presentation. Combined with Angular's Dependency Injection, RxJS, and HttpClient, services enable developers to build scalable, maintainable, and testable enterprise applications.
Key Takeaways
- ✔ Angular Services encapsulate reusable business logic.
- ✔ Use
@Injectable()to enable Dependency Injection. - ✔ Prefer
providedIn: 'root'for shared singleton services. - ✔ Keep components focused on presentation.
- ✔ Use
HttpClientinside services for API communication. - ✔ Share state using RxJS
BehaviorSubjector similar reactive patterns. - ✔ Follow the Single Responsibility Principle.
- ✔ Never instantiate services using
new. - ✔ Write unit tests for service logic.
- ✔ Angular Services are a core interview topic for every Angular developer.
Next Article
➡️ 40-HttpClient-Service-QA.md