Services Di

1 min read
Mid-level1 min read
Rapid overview

Services Di

TL;DR

Angular services are @Injectable singletons (when providedIn: 'root') that hold the logic, state, and HTTP calls components shouldn't own. Angular's hierarchical DI container wires them in via constructor parameters, which is what makes services swappable, mockable in tests, and the natural place to put cross-component state.

How it works

Creating Services

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root' // Singleton across entire app
})
export class UserService {
  private users: User[] = [];

  getUsers() {
    return this.users;
  }

  addUser(user: User) {
    this.users.push(user);
  }
}

Dependency Injection

// Inject in component
export class UserComponent {
  constructor(private userService: UserService) {}

  ngOnInit() {
    const users = this.userService.getUsers();
  }
}

// Inject in another service
@Injectable({
  providedIn: 'root'
})
export class AuthService {
  constructor(
    private http: HttpClient,
    private router: Router
  ) {}
}

Provider Scope

// Root level - singleton
@Injectable({
  providedIn: 'root'
})
export class SingletonService {}

// Module level
@NgModule({
  providers: [ModuleScopedService]
})
export class FeatureModule {}

// Component level - new instance per component
@Component({
  providers: [ComponentScopedService]
})
export class MyComponent {}

HttpClient

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  constructor(private http: HttpClient) {}

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>('/api/users');
  }

  createUser(user: User): Observable<User> {
    return this.http.post<User>('/api/users', user);
  }

  updateUser(id: string, user: User): Observable<User> {
    return this.http.put<User>(`/api/users/${id}`, user);
  }

  deleteUser(id: string): Observable<void> {
    return this.http.delete<void>(`/api/users/${id}`);
  }
}

Interceptors

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = localStorage.getItem('token');

    if (token) {
      const cloned = req.clone({
        headers: req.headers.set('Authorization', `Bearer ${token}`)
      });
      return next.handle(cloned);
    }

    return next.handle(req);
  }
}

// Register in module
providers: [
  { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]

See also