라떼군 이야기
Angular 18에서 HttpClientModule Deprecated 경고 해결 및 provideHttpClient 마이그레이션 가이드
Problem
Angular 프로젝트를 18 버전으로 업그레이드하거나 새로운 프로젝트를 시작할 때, 기존에 HTTP 통신을 위해 사용하던 HttpClientModule에 deprecated 경고가 발생하는 상황입니다.
Angular 17 이전까지는 AppModule의 imports 배열에 HttpClientModule을 추가하는 것이 표준이었습니다. 하지만 이제는 해당 모듈을 사용할 때 취소선이 그어지거나 “HttpClientModule is deprecated"라는 메시지가 나타나며, 개발자는 이를 대체할 새로운 설정 방식을 찾아야 합니다.
Background
Angular는 최근 몇 년간 NgModule 중심의 아키텍처에서 Standalone Component와 함수형 프로바이더(Functional Providers) 중심으로 생태계를 전환해 왔습니다.
사실 HttpClientModule은 내부적으로 provideHttpClient() 함수를 호출하여 서비스를 등록하는 역할만 수행하는 래퍼(Wrapper)였습니다. Angular 팀은 동일한 기능을 수행하는 두 가지 방법(모듈 방식 vs 함수 방식)이 공존함으로써 발생하는 혼란을 줄이고, 불필요한 모듈 클래스를 제거하여 번들 사이즈를 최적화하기 위해 HttpClientModule을 공식적으로 deprecated 처리했습니다.
Solution
해결 방법은 프로젝트가 NgModule 기반인지, 혹은 Standalone 기반인지에 따라 약간 다릅니다. 두 경우 모두 provideHttpClient() 함수를 사용하는 것이 핵심입니다.
1. NgModule 기반 애플리케이션 (기존 방식)
AppModule을 사용하는 프로젝트에서는 imports 배열에서 모듈을 제거하고, providers 배열에 함수를 추가합니다.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http'; // 모듈 대신 함수 임포트
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
// HttpClientModule, // [삭제] 더 이상 모듈을 임포트하지 않습니다.
// ...
],
declarations: [
AppComponent,
// ...
],
// [추가] providers 배열에 provideHttpClient() 함수를 호출하여 등록합니다.
providers: [provideHttpClient()],
bootstrap: [ AppComponent ]
})
export class AppModule {}
2. Standalone 기반 애플리케이션 (최신 방식)
Standalone 컴포넌트를 사용하는 최신 Angular 프로젝트에서는 app.config.ts 파일이나 bootstrapApplication 호출 부에서 설정합니다.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
// [추가] provideHttpClient를 등록합니다.
// withFetch()를 함께 사용하면 최신 Fetch API를 기반으로 동작하여 성능이 개선됩니다.
provideHttpClient(withFetch())
]
};
// main.ts (직접 부트스트랩 하는 경우)
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app.config';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
주의: 컴포넌트 레벨 임포트 에러
만약 컴포넌트의 imports 배열에 HttpClientModule을 넣고 있었다면 다음과 같은 에러가 발생할 수 있습니다.
Type ‘EnvironmentProviders’ is not assignable to type ‘Provider’.
HttpClient는 전역 서비스이므로 컴포넌트 레벨이 아닌 애플리케이션 루트 레벨(AppModule 또는 appConfig)에서 제공되어야 합니다. 컴포넌트에서는 단순히 제거하면 됩니다.
Deep Dive
왜 provideHttpClient()가 더 좋은가요?
- 구성의 유연성:
provideHttpClient()는 인자로 다양한 설정 기능(features)을 받을 수 있습니다. 예를 들어withFetch(),withInterceptors([...]),withXsrfConfiguration(...)등을 조합하여 훨씬 직관적으로 HTTP 클라이언트를 구성할 수 있습니다. - Fetch API 지원:
withFetch()를 사용하면 구형XMLHttpRequest대신 브라우저 네이티브fetchAPI를 사용합니다. 이는 Angular Universal(SSR) 환경에서 더 나은 호환성을 제공합니다.
실제 Angular 소스 코드
실제 Angular 소스 코드를 보면 HttpClientModule이 얼마나 단순했는지 알 수 있습니다. 사실상 아무런 로직 없이 프로바이더만 전달하고 있었습니다.
// Angular 소스 코드의 HttpClientModule 정의 (요약)
@NgModule({
providers: [
provideHttpClient(withInterceptorsFromDi())
],
})
export class HttpClientModule {}
따라서 provideHttpClient()로 전환하는 것은 기능적 손실 없이 코드를 현대화하는 안전한 작업입니다.
Conclusion
Angular 18에서의 HttpClientModule deprecation은 더 간결하고 모던한 Angular 개발 환경을 위한 변화입니다. 기존의 모듈 임포트 방식을 provideHttpClient() 함수 호출로 변경함으로써, 코드의 중복을 줄이고 최신 기능(Fetch API 등)을 더 쉽게 활용할 수 있습니다. 마이그레이션 과정은 매우 간단하므로 경고를 무시하지 말고 바로 적용하는 것을 권장합니다.