API چیست؛ مقایسهی REST، GraphQL و gRPC با مثال کد
API چیست و چطور دو نرمافزار با هم حرف میزنند؟ REST، GraphQL و gRPC را با مثال کد، جدول مقایسه و معیار انتخاب برای پروژهتان بشناسید.

فهرست مطالب
API چیست و چرا تقریباً هر نرمافزاری که هر روز با آن کار میکنید به آن وابسته است؟ رابط برنامهنویسی نرمافزار (Application Programming Interface) یا به اختصار API، قراردادی است که مشخص میکند یک برنامه چطور میتواند از برنامهی دیگر داده بخواهد یا کاری را به آن بسپارد. در این راهنما مفهوم API را از پایه توضیح میدهیم و سه سبک رایج آن را، یعنی REST، GraphQL و gRPC، با مثال کد کنار هم میگذاریم تا بدانید هرکدام کجا به کار میآید.
API چیست؛ یک تعریف ساده
منوی یک رستوران را در نظر بگیرید. شما وارد آشپزخانه نمیشوید و لازم نیست بدانید غذا چطور پخته میشود. منو میگوید چه چیزهایی را میتوانید سفارش دهید و گارسون سفارش شما را میبرد و نتیجه را برمیگرداند. API همان منو و گارسون است: فهرستی از کارهای مجاز، بههمراه قالب دقیق درخواست و پاسخ.
اپلیکیشن هواشناسی گوشی شما نمیداند سرور دادهها را در چه پایگاه دادهای نگه میدارد. فقط طبق قرارداد API درخواست میفرستد و پاسخی ساختاریافته میگیرد. همین جدایی باعث میشود تیم سرور بتواند پیادهسازی را عوض کند، بیآنکه اپلیکیشنها خراب شوند.
API فقط مخصوص وب نیست. سیستمعامل، کتابخانهها و مرورگر هم API دارند؛ مثلاً fetch و localStorage در مرورگر، یا متد map روی آرایههای جاوااسکریپت. اما در این مقاله تمرکز ما روی API تحت وب است؛ یعنی ارتباط دو برنامه از طریق شبکه.
اجزای اصلی یک API تحت وب
- نقطهی پایانی (Endpoint): آدرسی که درخواست به آن فرستاده میشود.
- درخواست و پاسخ (Request/Response): پیامی که کلاینت میفرستد و جوابی که سرور برمیگرداند.
- قالب داده: معمولاً JSON که برای انسان خواناست، یا قالبهای دودویی مثل Protocol Buffers.
- احراز هویت (Authentication): کلید API یا توکن که نشان میدهد درخواستدهنده کیست.
- مستندات: متن قرارداد؛ API بدون مستندات عملاً قابلاستفاده نیست.
REST؛ رایجترین سبک طراحی API
REST (Representational State Transfer) سبکی معماری است که روی فیلدینگ (Roy Fielding) آن را در فصل پنجم رسالهی دکترای خود تعریف کرد. REST پروتکل نیست؛ مجموعهای از قیدهاست: جدایی کلاینت و سرور، بیحالت بودن (Stateless) یعنی هر درخواست همهی اطلاعات لازم را با خودش دارد، قابلیت کش شدن پاسخها، رابط یکنواخت و سیستم لایهلایه.
در عمل، REST یعنی هر داده یک منبع (Resource) با آدرس مشخص است و با متدهای HTTP روی آن کار میکنید:
| متد | کاربرد | ایمن (فقط خواندنی) | Idempotent |
|---|---|---|---|
GET |
خواندن منبع | بله | بله |
POST |
ساختن منبع یا ارسال داده | خیر | خیر |
PUT |
جایگزینی کامل منبع | خیر | بله |
PATCH |
تغییر بخشی از منبع | خیر | خیر |
DELETE |
حذف منبع | خیر | بله |
متد Idempotent یعنی اگر یک درخواست را چند بار تکرار کنید، نتیجهی نهایی روی سرور همان یک بار است. این ویژگی برای تکرار خودکار درخواست بعد از قطعی شبکه اهمیت دارد.
پاسخها هم با کد وضعیت (Status Code) همراهاند: 200 یعنی موفق، 201 یعنی منبع ساخته شد، 400 یعنی درخواست نادرست است، 401 یعنی احراز هویت لازم است، 404 یعنی منبع پیدا نشد و 500 یعنی خطا در سرور رخ داده است.
یک درخواست REST واقعی
API عمومی GitHub نمونهی خوبی برای تمرین است. در ترمینال اجرا کنید:
curl https://api.github.com/users/octocat
پاسخ یک شیء JSON است که بخشی از آن این شکلی است:
{
"login": "octocat",
"id": 583231,
"html_url": "https://github.com/octocat"
}
همین درخواست را از داخل کد هم میتوانید بفرستید. این نمونه فقط از کتابخانهی استاندارد پایتون استفاده میکند (اگر تازه با پایتون آشنا میشوید، آموزش پایتون از صفر را ببینید):
import json
from urllib.request import urlopen
with urlopen("https://api.github.com/users/octocat") as response:
user = json.load(response)
print(user["login"], user["public_repos"])
برای ساختن داده معمولاً از POST با بدنهی JSON و توکن احراز هویت استفاده میشود. آدرس زیر نمونه است و به سرویس واقعی اشاره نمیکند:
curl -X POST https://api.example.com/v1/articles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"title": "What is an API?", "category": "web"}'
اگر میخواهید خودتان یک API ساده بسازید، بخش Route Handler در آموزش Next.js App Router نشان میدهد چطور در چند خط یک endpoint که JSON برمیگرداند راه بیندازید.
نقاط قوت REST: سادگی، ابزارهای فراوان، استفادهی مستقیم از کش HTTP و خوانایی. نقاط ضعف: دریافت دادهی اضافه (Over-fetching) وقتی فقط دو فیلد لازم دارید، و دریافت دادهی ناکافی (Under-fetching) وقتی برای یک صفحه باید چند endpoint را جداگانه صدا بزنید.
GraphQL؛ هرچه لازم دارید، نه بیشتر
GraphQL زبان پرسوجو برای API است که بر یک سیستم نوع (Type System) قوی تکیه دارد. سرور در یک اسکیما (Schema) انواع داده و روابطشان را تعریف میکند و کلاینت دقیقاً مشخص میکند کدام فیلدها را میخواهد. همهی درخواستها هم معمولاً به یک نقطهی پایانی واحد، مثلاً /graphql، فرستاده میشوند.
یک اسکیمای ساده:
type Author {
id: ID!
name: String!
}
type Article {
id: ID!
title: String!
author: Author!
}
type Query {
article(id: ID!): Article
}
و پرسوجویی که فقط عنوان مقاله و نام نویسنده را میخواهد:
query {
article(id: "42") {
title
author {
name
}
}
}
پاسخ دقیقاً همان شکل پرسوجو را دارد:
{
"data": {
"article": {
"title": "What is an API?",
"author": { "name": "DevNA Newsroom" }
}
}
}
در REST احتمالاً باید یک بار مقاله و یک بار نویسنده را جداگانه میگرفتید. GraphQL برای تغییر داده Mutation و برای دادهی بلادرنگ Subscription دارد و با قابلیت دروننگری (Introspection) میتوانید خود اسکیما را از سرور بپرسید؛ ابزارهای توسعه از همین قابلیت برای تکمیل خودکار استفاده میکنند.
نقاط ضعف GraphQL: چون همهچیز به یک آدرس میرود، کش HTTP بهسادگی REST کار نمیکند. کلاینت ممکن است پرسوجوی بسیار عمیق و سنگینی بفرستد، پس باید برای عمق و پیچیدگی پرسوجو محدودیت بگذارید. در سمت سرور هم اگر Resolverها بیدقت نوشته شوند، یک پرسوجو به دهها درخواست پایگاه داده تبدیل میشود (مشکل N+1).
gRPC؛ ارتباط سریع و دقیق بین سرویسها
gRPC چارچوبی متنباز برای فراخوانی رویهی دور (Remote Procedure Call) است. ایدهاش این است که کلاینت متدی را روی سروری دیگر صدا بزند، انگار که یک شیء محلی است. gRPC بهطور پیشفرض از Protocol Buffers هم بهعنوان زبان تعریف رابط و هم بهعنوان قالب پیام استفاده میکند و روی HTTP/2 کار میکند.
قرارداد در یک فایل .proto نوشته میشود:
syntax = "proto3";
package news.v1;
service ArticleService {
rpc GetArticle (GetArticleRequest) returns (Article);
rpc StreamLatest (StreamLatestRequest) returns (stream Article);
}
message GetArticleRequest {
string id = 1;
}
message StreamLatestRequest {
string category = 1;
}
message Article {
string id = 1;
string title = 2;
string author = 3;
}
سپس کامپایلر protoc از روی همین فایل برای زبانهای مختلف مثل Go، Java یا Python کد کلاینت و سرور تولید میکند. یعنی سرویسی به زبان Go و کلاینتی به زبان Python، بدون نوشتن دستی کد سریالسازی، با قراردادی مشترک با هم حرف میزنند.
gRPC چهار نوع متد دارد:
- Unary: یک درخواست، یک پاسخ؛ مثل فراخوانی تابع معمولی.
- Server streaming: یک درخواست و دنبالهای از پاسخها؛ مثل
StreamLatestدر مثال بالا. - Client streaming: دنبالهای از پیامها از کلاینت و یک پاسخ نهایی.
- Bidirectional streaming: هر دو طرف مستقل از هم پیام میفرستند.
نقاط ضعف gRPC: پیامهای دودویی برای انسان خوانا نیستند و اشکالزدایی ابزار مخصوص میخواهد. مرورگر هم نمیتواند مستقیم با سرویس gRPC حرف بزند و به gRPC-Web و یک پراکسی مثل Envoy نیاز دارد.
مقایسهی REST، GraphQL و gRPC در یک نگاه
| معیار | REST | GraphQL | gRPC |
|---|---|---|---|
| قالب رایج داده | JSON | JSON | Protocol Buffers (دودویی) |
| نقطهی پایانی | برای هر منبع یک آدرس | معمولاً یک آدرس | متدهای تعریفشده در سرویس |
| قرارداد | اختیاری (مثلاً OpenAPI) | اسکیمای اجباری | فایل proto اجباری |
| کش HTTP | ساده و طبیعی | دشوارتر | معمولاً در سطح برنامه |
| پشتیبانی مرورگر | کامل | کامل | با gRPC-Web و پراکسی |
| استریم | محدود | با Subscription | چهار حالت، از جمله دوطرفه |
| مناسب برای | API عمومی و CRUD | فرانتاند با دادهی ترکیبی | ارتباط داخلی میکروسرویسها |
کدام سبک API را انتخاب کنیم؟
- REST را انتخاب کنید اگر API عمومی میسازید، عملیات بیشتر خواندن و نوشتن ساده است و میخواهید هر توسعهدهندهای با یک
curlکار را شروع کند. - GraphQL را انتخاب کنید اگر چند کلاینت (وب، موبایل، پنل مدیریت) دارید که هرکدام برش متفاوتی از داده را میخواهند و تعداد رفتوبرگشتها برایتان مهم است.
- gRPC را انتخاب کنید اگر سرویسهای داخلی زیادی دارید، تأخیر و حجم پیام اهمیت دارد، به استریم نیاز دارید یا تیمها با زبانهای مختلف کار میکنند. اگر بین Rust و Go برای بکاند مردد هستید، هر دو پشتیبانی خوبی از gRPC دارند.
در بسیاری از سیستمهای واقعی این سه با هم ترکیب میشوند: سرویسها در داخل با gRPC حرف میزنند و یک لایهی REST یا GraphQL در لبه، داده را به مرورگر و اپلیکیشن موبایل میرساند.
نکتههای امنیتی و عملی برای هر API
- همیشه از HTTPS استفاده کنید و کلید API را هرگز در کد فرانتاند یا مخزن Git قرار ندهید.
- ورودیها را در سرور اعتبارسنجی کنید؛ به دادهای که کلاینت میفرستد اعتماد نکنید.
- برای جلوگیری از سوءاستفاده، محدودیت نرخ درخواست (Rate Limiting) بگذارید.
- مجوز دسترسی را برای هر شیء بررسی کنید، نه فقط برای هر endpoint. خطاهای رایج این حوزه را در راهنمای OWASP Top 10 مرور کردهایم.
- برای تغییرات ناسازگار نسخهبندی داشته باشید تا کلاینتهای قدیمی ناگهان از کار نیفتند.
نکته برای توسعهدهندههای ایران: برخی سرویسهای خارجی دسترسی از ایران را محدود میکنند. پیش از اینکه محصولتان را به یک API خارجی وابسته کنید، شرایط استفاده و دسترسپذیری آن را بررسی کنید و در کد برای قطعی یا رد شدن درخواست، مهلت زمانی (Timeout)، تلاش مجدد محدود و پیام خطای روشن در نظر بگیرید.
جمعبندی
API زبان مشترک نرمافزارهاست. REST با سادگی و هماهنگی کامل با HTTP هنوز انتخاب پیشفرض بیشتر پروژههاست، GraphQL انعطاف را به کلاینت میدهد و gRPC سرعت و قرارداد دقیق را بین سرویسها میآورد. هیچکدام برندهی مطلق نیست؛ معیار انتخاب، نوع کلاینتها، الگوی داده و نیازهای عملکردی پروژهی شماست. قدم بعدی عملی: با curl چند API عمومی را صدا بزنید و بعد یک endpoint سادهی REST برای پروژهی خودتان بسازید.




دیدگاهها
دیدگاهها پس از بررسی تحریریه منتشر میشوند. توهین، تبلیغ و لینکهای بیربط حذف میشوند؛ نقد فنی و مستند همیشه خوشآمد است.
هنوز کسی چیزی ننوشته. اولین دیدگاه را شما ثبت کنید.