ถ้ามี error เกิดขึ้นในระบบ เราสามารถใช้ Interceptor เพื่อจัดการได้อย่างรวดเร็วและเป็นระเบียบ และนี่คือเหตุผลหลัก ๆ ที่ควรใช้ Interceptor ในการจัดการข้อผิดพลาด
- จัดการ Error ในที่เดียว ทำให้โค้ดสะอาดขึ้น
- ปรับแต่ง Error Message ให้เป็นรูปแบบที่ต้องการ
โค้ดตัวอย่างสำหรับจัดการ Error ด้วย HttpErrorInterceptor
โค้ดชุดนี้จะสร้าง HttpErrorInterceptor เพื่อจัดการกับ error ที่เกิดขึ้นเมื่อเราเรียก API แล้วเกิดปัญหา โดยจะแปลงข้อมูล error ให้เป็นรูปแบบเฉพาะที่เรากำหนด เพื่อให้ง่ายต่อการแสดงผลหรือจัดการเพิ่มเติม
- สร้าง Interface และ Class เพื่อกำหนดโครงสร้าง Error
เรากำหนด IErrorStandard เป็น interface สำหรับเก็บรายละเอียด error และสร้าง ErrorStandard เพื่อใช้งานข้อมูล error ได้อย่างเป็นระบบ
export interface IErrorStandard {
resultCode: string;
resultDescription: string;
developerMessage: string;
}
export class ErrorStandard {
resultCode = '';
resultDescription = '';
developerMessage = '';
constructor(error?: Partial<IErrorStandard>) {
ObjectUtil.assignByTarget(this, error);
}
}
- Utility Class: ตัวช่วยในการจัดการกับ Object
ObjectUtil เป็น utility ที่จะช่วยให้เราสามารถจัดการข้อมูลภายใน object ได้สะดวก เช่น การคัดลอกข้อมูลจากแหล่งหนึ่งไปยังอีกแหล่งอย่างละเอียด หรือการแทนที่ค่าภายใน object ด้วยค่า null
export class ObjectUtil {
static assignByTarget(target: any, source: any) {
for (const [key, value] of Object.entries(target)) {
if (
typeof value === 'object' &&
value !== null &&
typeof source === 'object' &&
source.hasOwnProperty(key)
) {
ObjectUtil.assignByTarget(value, source[key]);
} else if (typeof source === 'object' && source && key in source) {
target[key] = source[key] !== undefined ? source[key] : value;
}
}
}
}
- สร้าง HttpErrorInterceptor สำหรับจัดการ HTTP Error
ใน HttpErrorInterceptor นี้ เราจะเช็คว่าเมื่อเกิด error ขึ้น ระบบจะตรวจสอบประเภท error แล้วแปลงข้อมูลไปยัง ErrorStandard และโยน error นี้กลับเพื่อให้จัดการใน component ที่เรียกใช้งาน
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse,
} from '@angular/common/http';
import { catchError, Observable } from 'rxjs';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest<unknown>,
next: HttpHandler,
): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
catchError((errorResponse: HttpErrorResponse) => {
if (typeof errorResponse.error === 'string') {
throw new ErrorStandard({ developerMessage: errorResponse.error });
}
throw new ErrorStandard(errorResponse.error);
}),
);
}
}
- ตั้งค่า Interceptor ในโมดูลหลัก
จากนั้นให้นำ HttpErrorInterceptor เข้าไปกำหนดไว้ในโมดูลหลักเพื่อให้ Interceptor นี้ทำงานตลอดทั้งแอปพลิเคชัน
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { HttpErrorInterceptor } from './http-error.interceptor';
@NgModule({
imports: [
HttpClientModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true,
},
],
})
export class AppModule { }
- ทดสอบ Error Handling ใน Component
เพื่อทดสอบ เราจะเรียก API ที่ไม่ถูกต้อง และให้ HttpErrorInterceptor จัดการ error ก่อนโยนกลับมายัง component เพื่อแสดงข้อมูล error ที่ถูกแปลงแล้วในรูปแบบ ErrorStandard
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-example',
template: `<button (click)="makeRequest()">Make Request</button>`,
})
export class ExampleComponent implements OnInit {
constructor(private http: HttpClient) {}
ngOnInit(): void {
this.makeRequest()
}
makeRequest() {
this.http.get('https://jsonplaceholder.typicode.com/invalid-url')
.subscribe({
next: (data) => console.log(data),
error: (err) => console.log('Error caught in component:', err),
});
}
}
เมื่อเรียกใช้งาน API นี้ เราจะเห็นว่ามี error ขึ้นและถูกจัดการตามที่กำหนดใน HttpErrorInterceptor โดยข้อมูล error ถูกแปลงเป็น ErrorStandard และแสดงใน console
สรุป
การใช้ HttpErrorInterceptor ใน Angular ช่วยให้การจัดการ error เป็นระบบมากขึ้น ไม่ว่าจะเป็นการจับ error ทั้งฝั่งเซิร์ฟเวอร์และฝั่งไคลเอนต์ พร้อมปรับแต่งการแสดงผลได้ตามต้องการ