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
| 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], 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
| 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
| export const environment = { production: false, baseUrl: 'https://test.api.example.com', };
|
1 2 3 4 5
| 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
| 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
| 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); }
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
| 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)); } }
|
참고