رویه های مناسب GraphQL | راهنمای کاربردی

۶۴ بازدید
آخرین به‌روزرسانی: ۱۲ مهر ۱۴۰۲
زمان مطالعه: ۴ دقیقه
رویه های مناسب GraphQL | راهنمای کاربردی

GraphQL یک زبان کوئری برای API-ها و یک محیط «زمان اجرا» (runtime) برای تأمین آن کوئری‌ها با داده‌های موجود است. runtime یک توصیف کامل و قابل درک از داده‌ها در API ارائه می‌کند و همچنین به کلاینت‌ها این امکان را می‌دهد که دقیقاً آنچه را که نیاز دارند و نه بیشتر از آن را تقاضا کنند. GraphQL از سوی فیسبوک به عنوان یک راهکار داخلی برای اپلیکیشن‌های موبایل توسعه یافته است و در ادامه به صورت متن-باز در اختیار جامعه توسعه‌دهندگان قرار گرفته است. در این مقاله با رویه های مناسب GraphQL آشنا خواهیم شد.

رویه های مناسب GraphQL

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

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

زمانی که دست به کار ایجاد اسکیما می‌شوید، ممکن است طراحی مدل‌های داده‌ای را دشوار بیابید. چندین روش برای انجام این کار وجود دارد و اغلب پیاده‌سازی‌ها به خوبی کار می‌کنند. مشکلات مختلف تنها زمانی رخ می‌نمایند که وارد بحث پیاده‌سازی شوید.

به طور کلی همواره خوب است که پلتفرم‌هایی که هم‌اینک از گراف‌کیوال استفاده می‌کنند را بررسی کنیم. Mutations یک مورد مناسب برای درک شیوه مدل‌سازی اشیای ورودی و خروجی و چگونگی افشای کوئری‌ها و موتاسیون‌ها محسوب می‌شود.

به عنوان یک قاعده کلی باید موتاسیون‌ها را تا حد ممکن کوچک نگه دارید. ورودی‌ها نیز باید همراه با نام‌گذاری گویا، انعطاف‌پذیر باشند.

1type Mutation {
2    addComment(input: AddCommentInput!): Comment
3}
4
5input AddCommentInput {
6  userId: ID
7  body: String
8}
9
10type Comment {
11  body: String
12}

موتاسیون به نام addComment ساده منسجم و روشن است. این جهش یا موتاسیون یک ورودی به نام می‌گیرد و یک مقدار به نام Comment بازگشت می‌دهد. ما یک مادیفایر غیر تهی (!) به کار می‌گیریم تا مطمئن شویم که payload ورودی نمی‌تواند تهی باشد. نکته‌ای که در اینجا باید مطمئن باشیم این است که شیوه ایجادشدن/ به‌روز شدن را بازگشت می‌دهیم. به این ترتیب کلاینت می‌تواند حالت را به‌روزرسانی کند تا کاربر بداند که آیا چیزی به‌روزرسانی شده یا نه.

از اشیای تودرتو برای کاهش فراخوانی‌های شبکه بهره بگیرید

نوع Comment در مثال قبلی یک نوع ساده بود که تنها یک فیلد داشت. فرض کنید می‌خواهیم userId را به عنوان بخشی از Comment بازگشت دهیم. یک رویکرد ممکن می‌تواند به صورت زیر باشد:

1type Comment {
2  body: String
3  userId: ID
4}

با این که این مثال می‌تواند شبیه یک رویکرد سریع و آسان به نظر برسد، اما یک مشکل کوچک وجود دارد. userId خودش نمی‌تواند برای فرانت‌اند مفید باشد و در نهایت باید یک فراخوانی انجام دهد تا کاربر با userId واکشی کند. این وضعیت کاملاً نامناسب است و امکان بهره‌برداری از همه توان گراف‌کیوال را فراهم نمی‌سازد. در GraphQL بسیار بهتر است که انواع خروجی را به صورت تودرتو دربیاوریم. به این ترتیب می‌توانیم همه چیز را با یک درخواست منفرد فراخوانی کنیم و همچنین عملیات کش‌کردن و دسته‌سازی را با data loader اجرا کنیم. این رویکرد شامل ارسال User در Comment است و به صورت زیر اجرا می‌شود:

1type Comment {
2  body: String
3  user: User
4}
5
6type User{
7  id: ID
8  name: String
9}

کوئری مربوطه به صورت زیر است:

1query getComments {
2  comment {
3    body
4    user{
5      id
6      name
7    }
8  }
9}

استفاده از مدیریت خطای مناسب

این یکی از نکاتی است که تقریباً همه افراد در آغاز استفاده از گراف‌کیوال فراموش می‌کنند و زمانی که اپلیکیشن بسیار بزرگ می‌شود، امکان پوشش دادن همه خطاها دشوار می‌شود. شاید بحث مدیریت خطا در GraphQl کمی پیچیده باشد، چون پاسخ همواره دارای یک حالت HTTP به صورت 200 OK است. اگر درخواستی ناموفق باشد، پاسخ JSON payload شامل فیلد روت به نام errors خواهد بود که جزییاتی در مورد علت شکست ارائه می‌کند. بدون مدیریت مناسب خطاها، پاسخ می‌تواند به صورت زیر باشد:

1{
2  "errors": [
3    {
4      "message": "Internal Server Error(s) while executing query"
5    }
6  ],
7  "data": null
8}

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

1{
2  "errors": [
3    {
4      "message": 
5      "Exception while fetching data (/getCar) : Car with name = B Class not found",
6      
7      "path": [
8        "getCar"
9      ],
10      "extensions": {
11        "parameters": {
12          "name": "B Class"
13        },
14        "classification": "DataFetchingException"
15      }
16    }
17  ],
18  "data": null
19}

از اینترفیس‌ها و Union‌-ها برای تجرید استفاده کنید

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

Union یک نوع شیء است که اشیای زیادی را بازنمایی می‌کند.

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

به مثال زیر توجه کنید. Profile یک اینترفیس است که از سوی User و همچنین Company پیاده‌سازی شده است. چند فیلد الزامی وجود دارند. فیلدهای دیگری نیز بر اساس نوع و الزامات متفاوت اضافه می‌شوند.

1interface Profile {
2  id: ID
3  name: String
4}
5
6type User implements Profile {
7  id: ID
8  name: String
9  age: Int
10}
11
12type Company implements Profile {
13  id: ID
14  name: String
15  address: String
16}

در مواردی که یک کوئری دارید که دو نوع بازگشت می‌دهد می‌توانید از Unuion-های مشابه استفاده کنید. به این ترتیب کوئری search می‌تواند یکی از نوع‌های User یا Compamny را بازگشت دهد:

1union SearchResult = User | Company
2
3type User {
4  name: String
5  age: Int
6}
7
8type Company {
9  name: String
10  address: Int
11}
12
13type SearchQuery {
14  firstSearchResult: SearchResult
15}

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

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

1query getFriends {
2  user {
3    friends {
4      ...friendFields
5    }
6    mutualFriends {
7      ...friendFields
8    }
9  }
10}
11
12fragment friendFields on User {
13  id
14  name
15  profilePic
16}

فرگمان‌ها با استفاده از عملگر اسپرد (...) مصرف می‌شوند. به این ترتیب مقدار زیادی از حجم کدهای تکراری کاسته می‌شود.

سخن پایانی

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

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

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