اهمیت GraphQL برای توسعه دهندگان فرانت اند — راهنمای کاربردی

۱۱۱ بازدید
آخرین به‌روزرسانی: ۲۹ شهریور ۱۴۰۲
زمان مطالعه: ۸ دقیقه
اهمیت GraphQL برای توسعه دهندگان فرانت اند — راهنمای کاربردی

فیسبوک در سال 2015 GraphQL را به جامعه توسعه‌دهندگان معرفی کرد. GraphQL که زمانی یک پروژه تحقیقاتی داخلی فیسبوک بود، به سرعت به استاندارد محبوب جدیدی برای توسعه API تبدیل شد. این زبان از آن زمان تا به اکنون به رشد سریع خود چه بر اساس کاربرد و چه محبوبیت تداوم بخشیده است. شرکت‌های بزرگ زیادی مانند گیت‌هاب، Paypal و Airbnb، هم‌اینک این زبان را در بخشی از مجموعه بک‌اند خود به خدمت گرفته‌اند. در این مقاله به بررسی GraphQL یک زبان API مناسب برای توسعه دهندگان فرانت‌اند می‌پردازیم.

GraphQL چیست؟

GraphQL یک زبان کوئری برای API-ها است. آن را می‌توان معادلی برای REST دانست که امروزه رایج‌ترین استاندارد برای ساخت API به شمار می‌رود. GraphQL به کلاینت‌ها امکان می‌دهد که نه‌تنها داده‌هایی که نیاز دارند را واکشی کنند، بلکه نگاشت روابط بین انواع داده را نیز تسهیل می‌کند و به همین دلیل گراف نام دارد.

توسعه یک API با GraphQL از طریق تعریف کردن یک اسکیما که انواع داده مورد استفاده در API، روابط بین آن انواع و کوئری‌ها و تغییراتی که امکان اجرای عملیات CRUD را روی داده‌ها فراهم می‌سازند را توصیف می‌کند. برای کسب اطلاعات بیشتر در مورد ساختار و روش‌های مختلف پیاده‌سازی یک API با GraphQL می‌توانید از مستندات رسمی این زبان (+) کمک بگیرید.

روندهای جدید در زمینه توسعه دهنگان فرانت‌اند

در ابتدا به بررسی سه روند مهم اخیر در زمینه توسعه دهندگان فرانت‌اند می‌پردازیم که در طی پنج سال اخیر رخ داده‌اند.

ابزارهای بهتر

اکوسیستم جاوا اسکریپت هرگز چنین پایدار نبوده است. از سال 2015 تعداد ماژول‌های npm شش برابر شده است. با این که بخشی از این رشد از ظهور Node.js نشأت می‌گیرد، اما بخش عمده دیگری نیز از شکوفایی فریمورک‌های فرانت‌اند منبعث شده است. هر یک از این فریمورک‌ها ابزارهای مختلفی را برای کمک به تجربیات تست کردن و توسعه عرضه کرده‌اند.

تایپ اسکریپت

در پیمایش اخیری (+) که از سوی npm اجرا شده است، گزارش شده که 61% از توسعه دهندگان فرانت‌اند از تایپ‌اسکریپت استفاده می‌کنند که نسبت به پیمایش قبلی افزایشی 31 درصدی را نشان می‌دهد. توسعه دهندگان فرانت‌اند، قبلاً بیشتر باگ‌ها را زمانی می‌یافتند که کد را در مرورگر اجرا می‌کردند. با ظهور بررسی نوع به صورت استاتیک، خطاهای زیادی در مراحل قبل‌تر به دام می‌افتند و حتی بسیاری از آن‌ها در IDE و هنگام نوشتن کد مشخص می‌شوند.

افزایش منطق اپلیکیشن در سمت کلاینت

با بهبود سرعت اینترنت، مرورگرها و پردازنده‌ها، کلاینت‌های فرانت‌اند اینک می‌توانند بسیاری از عملیاتی که قبلاً در بک‌اند اجرا می‌شد را خود انجام دهند.

قابلیت‌های GraphQL در مسیر این روندها

GraphQL واجد قابلیت‌هایی است که امکان بهبود هر یک از سه حوزه پیش‌گفته را فراهم می‌سازد. این قابلیت‌ها موجب شده‌اند که GraphQL به بهترین زبان API برای فرانت‌اند تبدیل شود. کارهایی که زمانی با استفاده از REST API انجام آن دشوار یا ناممکن بود، اینک با استفاده از GraphQL در طی چند دقیقه انجام می‌شوند. در ادامه این قابلیت‌های GraphQL را مورد بررسی بیشتری قرار می‌دهیم.

بررسی اسکیمای GraphQL به عنوان یک ابزار بهتر

هر API در GraphQL صرف‌نظر از زبان یا فریمورکی که با آن ساخته شده است، به همراه مستنداتی در مورد هر درخواست معتبر که می‌توان ساخت عرضه می‌شود. همچنین پاسخی که کلاینت می‌دهد نیز مستندسازی شده است. این امر به توسعه‌دهندگان امکان می‌دهد که ابزارهای پایداری بسازند که برای کارکردهای هر API خاص در GraphQL سفارشی‌سازی شده است.

نتیجه این وضعیت ابزارهایی مانند GraphiQL (+) و GraphQL-faker (+) هستند که دو مورد از پروژه‌های اوپن‌سورس محسوب می‌شوند که باید در جعبه ابزار هر توسعه‌دهنده فرانت اندی موجود باشند.

GraphiQL امکان تست کوئری‌ها و تولید مستندات API را به صورت درجا فراهم می‌سازد. تیم موجود در OneGraph حتی یک کاوشگر (+) ساخته‌اند که امکان نوشتن و تست کوئری‌ها و تغییرات را به صورت تعاملی فراهم می‌سازد.

GraphQL-faker امکان ساخت و راه‌اندازی یک سرویس API ساختگی را در طی چند دقیقه می‌دهد که API ساخته شده با GraphQL را تقلید می‌کند. GraphQL-faker با استفاده از بررسی درونی می‌تواند شکل دقیق پاسخ به هر درخواست را پیش‌بینی کند و آن‌ها را به صورت پایداری جعل کند. کافی است اسکیمای API-ی خود را به‌روزرسانی کند تا GraphQL-faker با پیاده‌سازی کوئری‌ها و تغییرات جدید در بک‌اند، به کمک توسعه‌دهندگان فرانت‌اند بیاید.

مواردی که در این بخش مورد اشاره قرار دادیم، صرفاً دو مورد از ده‌ها ابزار اوپن‌سورس هستند که به لطف ظرفیت‌های بررسی درونی GraphQL در اختیار ما قرار گرفته‌اند.

چرا GraphQL بهتر از REST است؟

وقتی REST API را در نظر می‌گیریم، نزدیک‌ترین معادل GraphQL چیزی به نام Swagger است. اما به جز API-هایی که با Swagger ساخته می‌شوند، نوشتن همه پارامترها و پاسخ‌های درخواست برای هر نقطه انتهایی در API کاری بسیار زمان‌بر محسوب می‌شود. GraphiQL بی‌درنگ روی هر API در GraphQL عمل می‌کند. همانند تقلید داده‌ها که از سوی GraphQL-faker انجام می‌شد، همین مسئله در مورد کوئری‌های REST API نیز اجرا می‌شود و پاسخ‌های جعلی برای هر نقطه انتهایی نوشته می‌شود و با تکمیل یافتن API این موارد نیز به طور پیوسته تغییر می‌یابند. این کار می‌تواند پیچیده و مستعد خطا باشد.

اسکیمای دارای نوع GraphQL به عنوان مکملی عالی برای تایپ اسکریپت

تایپ‌اسکریپت به تیم‌های مهندسی امکان می‌دهد که از سرعت جاوا اسکریپت به همراه گاردهای حفاظتی که به حرکت ایمن کمک می‌کنند بهره‌مند شوند.

GraphQL یک زبان کامل API برای تکمیل تایپ‌اسکریپت محسوب می‌شود، زیرا دارای نوع‌بندی قوی است. این مسئله همراه با الگوریتم‌های بررسی داخلی که قبلاً اشاره کردیم، به این معنی است که می‌توانید از ابزارهایی مانند Apollo Codegen برای اعتبارسنجی خودکار کوئری‌ها و تغییراتی که در پروژه ایجاد می‌کنید و برای تولید خودکار اینترفیس‌های تایپ‌اسکریپت که انواعی را به پاسخ‌های مورد انتظار اضافه می‌کنند بهره بگیرید. بدین ترتیب برای مثال می‌توانیم یک اسکیمای GraphQL داشته باشیم که به صورت زیر باشد:

1type Character {
2  name: String!
3  age: Int!
4}
5type Query {
6  character(age: Int!): Character
7}

و در فرانت‌اند کوئری زیر را تعریف کرده باشیم:

1# src/queries/getCharacter.gql
2query GetCharacter {
3  character(age: 21) {
4    name
5    age
6  }
7}

برای تولید خودکار انواع برای این کوئری، پکیج ابزارهای Apollo را به صورت گلوبال با دستور زیر نصب می‌کنیم:

npm install -g Apollo

سپس دستور زیر را از ریشه پروژه اجرا می‌کنیم:

1apollo codegen:generate --endpoint=https://[GRAPHQL_SERVER] \
2	--target=typescript --includes=src/**/ --tagName=gql \
3	--addTypename --outputFlat=src/graphql/types

بدین ترتیب یک فایل تایپ‌اسکریپت در مسیر زیر ایجاد می‌شود:

src/graphql/types/getCharacter.ts

محتوای این فایل به صورت زیر است:

1// ====================================================
2// GraphQL mutation operation: getCharacter
3// ====================================================
4export interface getCharacter_character {
5  __typename: 'Character';
6  name: string;
7  id: string;
8}
9export interface getCharacter {
10  character: getCharacter_character | null;
11}

اگر از React برای ساخت کامپوننت <CharacterBio> استفاده می‌کنید، که به یک نوع Character در GraphQL نگاشت می‌شود، می‌توانید از آن اینترفیس در کامپوننت کاربردی ری‌اکت خود به صورت زیر بهره بگیرید:

1import { getCharacter_character } from './gen/queries';
2const CharacterBio: React.FC<getCharacter_character> = props => (
3  <div className="character">
4    <h3 className="character__name">{props.name}</h3>
5    <span className="character__age">({props.age})</span>
6  </div>
7);

توجه کنید که کد فوق تایپ‌اسکریپت است و نه جاوا اسکریپت محض. فرانت‌اند شما به طور مداوم بررسی می‌کند که کوئری‌هایی که می‌خواهید بسازید، بر اساس اسکیمای API مربوطه، ممکن باشند و این که از پاسخ در کامپوننت‌ها به طرز صحیحی استفاده کنید. این بدان معنی است که هرگز در مورد این که پاسخ ارسالی از سوی یک درخواست API چه شکلی دارد، شگفت‌زده نخواهد شد.

چرا این وضعیت بهتر از REST است؟

این نوع از اعتبارسنجی در زمان کامپایل، در مورد API-های REST ناممکن است. حتی اگر API از استانداردهای OpenAPI پیروی کند، هیچ ابزاری برای یکپارچه‌سازی آن تا این حد تمیز با تایپ‌اسکریپت وجود ندارد. این بدان معنی است که شما مجبور هستید خطاها را تنها زمانی که در کنسول شبکه در مرورگر ظاهر می‌شوند اصلاح کنید.

کوئری انعطاف‌پذیر در GraphQL به عنوان منطق پیشرفته اپلیکیشن در سمت کلاینت

یکی از مشکلات REST API منجر به این شده است که مجبور شویم بک اندی طراحی کنیم که دقیقاً همراستا با View-های مورد نیاز در فرانت‌اند عمل کند. این وضعیت می‌تواند محدودکننده باشد، زیرا هر بار که به یک view جدید نیاز داریم، تیم‌های بک‌اند باید یک نقطه انتهایی جدید برای استفاده در فرانت‌اند طراحی و پیاده‌سازی کنند.

برای نمونه فرض کنید یک پروژه ایجاد کرده‌اید که باید یک دسته از اشیای task را ذخیره‌سازی کنید. هر task فیلدهای زیر را دارد:

  • Summary – خلاصه متن وظیفه
  • Completed – مقدار بولی که کامل شدن یا نشدن آن را تعیین می‌کند.
  • Assignee –یک id شیء user منفرد که وظیفه به آن انتساب یافته است.

GraphQL انعطاف‌پذیری لازم برای واکشی تنها فیلدها و داده‌های مورد نیاز برای انجام یافتن یک کار مشخص را در اختیار توسعه‌دهندگان فرانت‌اند قرار می‌دهد. همچنین برای ساده‌تر کردن واکشی داده‌های رابطه‌ای طراحی شده است. بدین ترتیب توسعه‌دهندگان فرانت‌اند می‌توانند قدرت کوئری زدن یک زبان مانند SQL را در ساختاری به نظم بکشند که شبیه JSON باشد.

با استفاده از GraphQL، اسکیمای این اپلیکیشن چیزی مانند زیر خواهد بود:

1type User {
2  id: String!
3  name: String!
4  email: String!
5  photo: String!
6}
7type Task {
8  summary: String!
9  completed: Boolean!
10  assignee: User!
11}
12type Query {
13  tasks(userId: Int): [Task!]!
14}

این بدان معنی است که شما بی‌درنگ این توان را دارید که وظایف مختلف را با هر فیلتری کوئری بزنید و هر نوع وظیفه انتساب یافته را به همراه نام و تصویر مربوطه واکشی کنید. همه این کارها را می‌توان با یک کوئری انجام داد:

1# Fetch all tasks for user 1
2query {
3  tasks(userId: 1) {
4    summary
5    completed
6  }
7}
8# Fetch all tasks for all users, along with the assignee's name and photo.
9query {
10  tasks {
11    summary
12    completed
13    assignee {
14      name
15      photo
16    }
17  }
18}

از این جهت که ساختار آن شباهت زیادی به JSON دارد، هر توسعه‌دهنده فرانت‌اندی با آن آشنا است و به راحتی می‌تواند از آن استفاده کند. از سوی دیگر کاملاً قدرتمند نیز هست.

چرا بهتر از REST است؟

هنگام استفاده از REST API همه وظایف برای یک کاربر مفروض بسیار آسان هستند. کافی است یک نقطه انتهایی Get داشته باشیم که بر اساس assignee فیلتر شود. بنابراین از چیزی مانند زیر استفاده می‌کنیم:

/api/tasks/:userId.

ما اگر اینک بخواهیم یک استریم از همه وظایف را همراه با نام‌ها و تصاویر کاربران که انتساب یافته‌اند نمایش دهیم، چه باید بکنیم؟ اینک شیء task ما تنها id کاربر را بازگشت می‌دهد. از این رو دو گزینه پیش رو داریم:

پاسخ را طوری ارتقا می‌دهیم که شامل نام و تصویر کاربر نیز باشد. این فیلدها ممکن است همواره استفاده نشوند اما همواره واکشی خواهند شد.

یک نقطه انتهایی ثانویه راه‌اندازی می‌شود که همه کاربران را با id، تصویر و نامشان بازگشت می‌دهد و سپس آن‌ها را در فرانت‌اند تطبیق می‌دهد.

در مثال GraphQL فوق، می‌توانید هر دو این کارها را با کوئری یکسانی انجام دهید. زمانی که می‌خواهید وظایف مربوط به کاربران مختلف را به دست آورید، باید آرگومان ورودی را حذف کنید. هنگامی که وظایف را برای فقط یک کاربر می‌خواهید، باید userId را بیاورید، اما نام و تصویر برای هر وظیفه واکشی نمی‌شود.

نواقص GraphQL کدام هستند؟

هنگام استفاده از GraphQL نیز مسلماً نواقصی به خصوص برای توسعه‌دهندگان فرانت‌اند وجود دارند.

دیباگ کردن دشوارتر است

یک تفاوت عمده بین REST API و API-های GraphQL این است که دومی تنها یک نقطه انتهایی دارد. همه درخواست‌ها از طریق POST به آن نقطه انتهایی ارسال می‌شوند و از این رو دیباگ کردن پاسخ‌ها از یک API در فرانت‌اند در مواردی که تنها یک دسته از درخواست‌ها مانند زیر دیده می‌شوند، ممکن است بسیار دشوار باشد:

GraphQL یک زبان API مناسب

همچنین GraphQL از کدهای خطا چنان‌که REST API استفاده می‌کند، بهره نمی‌گیرند. مجموعه گسترده‌ای از وضعیت‌های HTTP از پیش تعریف شده وجود دارند که برای پوشش اغلب مشکلات یک REST API به توسعه‌دهندگان فرانت‌اند مورد استفاده قرار می‌گیرد. این پروتکل استاندارد موجب آسان‌تر شدن ارسال خطا از REST API به فرانت‌اند می‌شود. از سوی دیگر، GraphQL راهنمایی بسیار اندکی در مورد مدیریت خطا ارائه می‌کند. تنها الزام این است که یک خطا با یک فیلد message بازگشت یابد که یک توصیف string از مشکل ارائه می‌کند. کلاینت‌های فرانت‌اند مانند Apollo به تحلیل این خطاها کمک می‌کنند، اما از آنجا که هیچ پروتکل ارتباطی مانند کدهای وضعیت HTTP وجود ندارند، هر اپلیکیشن باید برای رفع نیازهای خود یک چنین چیزی را طراحی کند.

افزایش پیچیدگی

با این که هنگام استفاده از GraphQL می‌توان کوئری‌های پیچیده‌ای را به روش نسبتاً آسانی نوشت، اما از سوی دیگر ممکن است نوشتن کوئری‌های ساده نیز و تحلیل کردن آن‌ها نیز اندکی دشوارتر باشد. برای نمونه فرض کنید می‌خواهید یک task خاص را با id شماره 1 از API بازیابی کرده و آن را در کنسول لاگ کنید. با استفاده از REST می‌توانید کد زیر را برای واکشی در فرانت‌اند بنویسید:

1fetch('https://api.myapp.com/tasks/1')
2  .then(res => res.json())
3  .then(task => console.log(task))
4  .catch(e => throw Error(e));

کد فوق چنان‌که می‌بینید کاملاً سرراست است. برای انجام همین کار در GraphQL باید فراخوانی واکشی زیر را بنویسید:

1fetch('https://api.myapp.com/graphql', {
2  method: 'POST',
3  body: JSON.stringify({
4    query: `query GetTask($id: Int!) {
5	task(id: $id) {
6          id
7          summary
8	    assignee {
9	      name
10	      photo
11	    }
12	  }
13	}`,
14    variables: { id: 1 }
15  })
16})
17  .then(res => res.json())
18  .then(res => console.log(res.data.task))
19  .catch(e => throw Error(e));

چنان‌که می‌بینید حجم کد برای یک عملیات نسبتاً ساده بالا است. با این که ممکن است این روش به کد پایدارتری منجر شود، اما یک سربار به صورت درک سازماندهی درخواست‌های POST در GraphQL نیز به همراه خود دارد.

سخن پایانی

فریمورک‌های فرانت‌اند به صورت مداوم در حال تغییر هستند، اما پیشرفت‌های اخیر که در این جامعه رخ داده است مسیر را برای این که GraphQL به عنان یک مکمل عالی برای فناوری‌های فرانت‌اند مطرح شود کاملاً آماده ساخته‌اند. GraphQL نیز مانند هر نوع فناوری نوظهور دیگر دارای یک منحنی یادگیری غیر آسان است و از این رو شاید همواره بهترین گزینه نباشد. اما با در نظر گرفتن تجربیات کاربری، زمانی که از GraphQL استفاده کنید، دیگر نمی‌توانید آن را رها کنید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
midtype
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *