[Angular] HttpClient 사용 방법

Angular 개발 시 프로젝트 초기에 api 통신에 대해 설정 파일을 생성하고 설정해 두면 작업하기가 편합니다.
Angluar는 @angular/common 안에 존재하는 http 패키지를 사용하면 됩니다.

import

http 작업을 하기 위해 src/app.module.ts 파일에 HttpClientModule을 import 해야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// src/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
declarations: [AppComponent],
// BrowserModule 다음에 HttpClientModule를 작성해야 한다
imports: [BrowserModule, HttpClientModule, AppRoutingModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

ApiService 구축

api는 전역에서 사용하는 것이기 때문에 service로 만든다.
src/app/services 폴더 아래에 api.service.ts 파일을 만들었다.

1
2
3
4
5
6
7
8
9
// src/app/services/api.service.ts
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class ApiService {
constructor() {}
}

Injectable 이기 때문에 다른 module 에서 import 하지 않아도 바로 사용할 수 있다.

baseUrl 설정

이제 불러 올 api의 baseUrl을 설정해준다.

1
2
3
4
5
6
7
8
9
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class ApiService {
public BASE_URL = 'https://webtoon-crawler.nomadcoders.workers.dev';

constructor(private http: HttpClient) {}
}

보통 BASE_URL은 각 프로젝트의 환경 별로 다르게 설정 가능하다.

1
2
3
4
5
// src/environments/environments.ts
export const environment = {
production: false,
baseUrl: 'https://test.api.example.com',
};
1
2
3
4
5
// src/environments/environment.prod.ts
export const environment = {
production: true,
baseUrl: 'https://api.example.com',
};

위의 처럼 설정한 후 src/api/api.service.ts에 다음과 같이 불러와 사용하면 된다.

1
2
3
4
5
import { environment } from 'environments/environment';
// ...생략
export class ApiService {
public BASE_URL = environment.baseUrl;
}

http 메서드 설정

HTTP 요청 메서드에서 자주 사용하는 GET, POST, PUT, DELETE를 사용하는 함수를 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/api/api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class ApiService {
public BASE_URL = 'https://webtoon-crawler.nomadcoders.workers.dev';

constructor(private http: HttpClient) {}

get<T>(endPoint: string): Observable<T> {
return this.http.get<T>(`${this.BASE_URL}${endPoint}`);
}

post<T>(endPoint: string, body: any): Observable<T> {
return this.http.post<T>(`${this.BASE_URL}${endPoint}`, body);
}

put<T>(endPoint: string, body: any): Observable<T> {
return this.http.put<T>(`${this.BASE_URL}${endPoint}`, body);
}

delete<T>(endPoint: string): Observable<T> {
return this.http.delete<T>(`${this.BASE_URL}${endPoint}`);
}
}

Angular의 http의 return 타입은 모두 Observable 이기 때문에, 할당할 변수의 타입도 Observable로 지정해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// src/app/app.components.ts
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { ApiService } from 'app/services/api.service';

interface WebToonInfo {
id: string;
title: string;
thumb: number;
}

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
webToons$: Observable<WebToonInfo[]>;

constructor(private api: ApiService) {
this.webToons$ = this.api.get('/today');
this.webToons$.subscribe(console.log); // console 확인
}

ngOnInit(): void {}
}

Error 처리

만약 에러를 처리하고 싶다면, 각 api 요청마다 설정할 수도 있지만 api.service.ts 에서 설정 해줘도 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/app/services/api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class ApiService {
// ... 생략

private handleError(error: HttpErrorResponse) {
if (error.status === 0) {
console.error('Error:', error.error);
} else {
console.error(`Backend error ${error.status}, ${error.error}`);
}
return throwError('예기치 못한 에러가 발생했습니다. 다시 시도해주세요.');
}

get<T>(endPoint: string): Observable<T> {
return this.http.get<T>(`${this.BASE_URL}${endPoint}`).pipe(catchError(this.handleError));
}
}

참고

Share