ویرگول
ورودثبت نام
garmabi.mohammad73
garmabi.mohammad73Senior Software Engineer با تمرکز بر Frontend، React و TypeScript. علاقه‌مند به Software Architecture، System Design، Open Source و ساخت ابزارهای ساده و مقیاس‌پذیر.
garmabi.mohammad73
garmabi.mohammad73
خواندن ۴ دقیقه·۱ ماه پیش

آموزش Angular و tanstack-fetch؛ ساخت HTTP Client تایپ‌سیف با TypeScript

توضیحات مقاله: در این آموزش یاد می‌گیریم چطور با tanstack-fetch، Angular Dependency Injection و TanStack Query یک لایه‌ی API قابل‌استفاده‌ی مجدد، تایپ‌سیف و پشتیبان از لغو درخواست بسازیم.

در پروژه‌های Angular معمولاً کار با API با چند درخواست ساده شروع می‌شود؛ اما با بزرگ‌تر شدن پروژه، مدیریت درخواست‌ها، خطاها، تایپ پاسخ‌ها و لغو درخواست‌ها می‌تواند به یک چالش تبدیل شود.

اگر هر کامپوننت منطق درخواست HTTP خودش را داشته باشد، نگهداری و یکپارچه‌سازی رفتارها دشوارتر خواهد شد.

در این مقاله، یک روش برای جداسازی لایه‌ی HTTP از مدیریت وضعیت سرور را با استفاده از tanstack-fetch، Angular و TanStack Query بررسی می‌کنیم.

tanstack-fetch چیست؟

tanstack-fetch یک HTTP client مستقل مبتنی بر TypeScript است که برای استفاده در کنار الگوی برنامه‌نویسی TanStack Query طراحی شده است.

مسئولیت ابزارها را می‌توان این‌طور تقسیم کرد:

  • tanstack-fetch: ارسال درخواست HTTP و مدیریت خطاهای مرتبط با کلاینت.

  • TanStack Query: مدیریت چرخه‌ی عمر query و کش داده‌های سمت سرور.

  • Angular: مدیریت کامپوننت‌ها و Dependency Injection.

این پروژه توسط Mohammad Garmabi توسعه داده شده و یک پکیج رسمی از تیم TanStack نیست.

۱. نصب پکیج‌ها

ابتدا پکیج‌های موردنیاز را نصب می‌کنیم:

npm install tanstack-fetch npm install @tanstack/angular-query-experimental

این نمونه بر اساس API ارائه‌شده در مستندات Angular پروژه نوشته شده است. پیش از استفاده در محیط production، سازگاری نسخه‌های نصب‌شده را بررسی کنید.

۲. ساخت HTTP Client مشترک

بهتر است تنظیمات API را در یک محل مشخص نگه داریم:

// api.ts import { createFetch } from 'tanstack-fetch'; export interface User { id: number; name: string; email: string; } export const api = createFetch({ baseUrl: 'https://jsonplaceholder.typicode.com', });

در این مثال از یک API آزمایشی استفاده می‌کنیم. در پروژه‌ی واقعی می‌توانید آدرس API خودتان را قرار دهید.

۳. اتصال به Angular Dependency Injection

حالا client را به providerهای برنامه اضافه می‌کنیم:

import { bootstrapApplication } from '@angular/platform-browser'; import { provideFetchClient } from 'tanstack-fetch/angular'; import { api } from './api'; import { UsersComponent } from './users.component'; bootstrapApplication(UsersComponent, { providers: [ provideFetchClient({ client: api }), ], });

پس از این مرحله، می‌توانیم در context معتبر Angular از injectFetch() برای دریافت client استفاده کنیم.

۴. دریافت داده با TanStack Query

در مثال زیر، فهرست کاربران را دریافت می‌کنیم و وضعیت درخواست را در رابط کاربری نمایش می‌دهیم.

import { Component } from '@angular/core'; import { injectQuery } from '@tanstack/angular-query-experimental'; import { injectFetch } from 'tanstack-fetch/angular'; import { isFetchError } from 'tanstack-fetch'; import { User } from './api'; @Component({ selector: 'app-users', standalone: true, template: ` @if (users.isPending()) { <p>در حال دریافت اطلاعات...</p> } @else if (users.isError()) { <p>{{ errorLabel() }}</p> } @else { <ul> @for (user of users.data(); track user.id) { <li>{{ user.name }} - {{ user.email }}</li> } </ul> } `, }) export class UsersComponent { private readonly api = injectFetch(); readonly users = injectQuery(() => ({ queryKey: ['users'], queryFn: ({ signal }: { signal: AbortSignal }) => this.api.get<User[]>('/users', { signal }), })); errorLabel(): string { const error = this.users.error(); return isFetchError(error) ? `خطای HTTP ${error.status}: ${error.message}` : 'دریافت اطلاعات ناموفق بود'; } }

این معماری چه مزایایی دارد؟

۱. تایپ‌سیف بودن پاسخ‌ها

با استفاده از get<User[]> نوع داده‌ی موردانتظار را مشخص می‌کنیم. این کار به خوانایی کد و تشخیص خطاهای تایپی کمک می‌کند؛ البته صحت واقعی داده‌های دریافتی از سرور را به‌تنهایی تضمین نمی‌کند.

۲. استفاده از Dependency Injection

به‌جای ساختن client در هر کامپوننت، از یک نمونه‌ی پیکربندی‌شده استفاده می‌کنیم.

۳. لغو درخواست با AbortSignal

سیگنال دریافتی از TanStack Query را به درخواست HTTP منتقل می‌کنیم:

queryFn: ({ signal }: { signal: AbortSignal }) => this.api.get<User[]>('/users', { signal })

این اتصال اجازه می‌دهد درخواست در صورت لغو شدن توسط چرخه‌ی عمر query، عملیات لغو را دریافت کند؛ مشروط به اینکه HTTP client سیگنال را به درخواست زیرین منتقل کند.

۴. جداسازی مدیریت خطا

تابع isFetchError() کمک می‌کند خطاهای مربوط به HTTP client را از خطاهای دیگر متمایز کنیم و پیام مناسب‌تری به کاربر نمایش دهیم.

۵. جداسازی HTTP از مدیریت وضعیت سرور

TanStack Query مسئول کش و چرخه‌ی عمر query است، درحالی‌که tanstack-fetch درخواست HTTP را انجام می‌دهد. این تفکیک از ترکیب شدن مسئولیت‌های متفاوت در یک کامپوننت جلوگیری می‌کند.

آیا همیشه باید از یک HTTP Client جداگانه استفاده کنیم؟

خیر. Angular ابزار داخلی HttpClient را هم در اختیار توسعه‌دهندگان قرار می‌دهد و برای بسیاری از پروژه‌ها کاملاً کافی است.

استفاده از یک client جداگانه زمانی ارزشمند است که به قراردادهای مشترک برای درخواست‌ها، تایپ پاسخ‌ها، مدیریت خطا یا یکپارچگی بیشتر با ابزارهای مدیریت server state نیاز داشته باشید.

هدف، پیچیده‌تر کردن معماری نیست؛ هدف این است که هر لایه مسئولیت مشخصی داشته باشد.

جمع‌بندی

با ترکیب Angular Dependency Injection، tanstack-fetch و TanStack Query می‌توان یک لایه‌ی API ساخت که درخواست‌های تایپ‌سیف را با مدیریت وضعیت سرور و امکان انتقال سیگنال لغو هماهنگ می‌کند.

اگر می‌خواهید جزئیات API و مثال‌های بیشتر را ببینید، مستندات پروژه در دسترس است:

  • راهنمای Angular در tanstack-fetch

  • مخزن GitHub پروژه

نویسنده: Mohammad Garmabi، توسعه‌دهنده‌ی نرم‌افزار و سازنده‌ی پروژه‌ی متن‌باز tanstack-fetch.

angulartypescriptجاوااسکریپتبرنامه نویسی
۱۰
۰
garmabi.mohammad73
garmabi.mohammad73
Senior Software Engineer با تمرکز بر Frontend، React و TypeScript. علاقه‌مند به Software Architecture، System Design، Open Source و ساخت ابزارهای ساده و مقیاس‌پذیر.
شاید از این پست‌ها خوشتان بیاید