مستندسازی API با OpenAPI؛ از فایل اولیه تا مستند قابل استفاده
مستندسازی API با OpenAPI یعنی همه endpointها، ورودی ها، خروجی ها و خطاهای سرویس را در یک فایل استاندارد توصیف کنی. از همین فایل می شه مستند تعاملی، سرور آزمایشی و کد کلاینت ساخت.

مستندسازی API با OpenAPI یعنی همه endpointها، ورودی ها، خروجی ها و خطاهای سرویست رو توی یه فایل استاندارد (YAML یا JSON) توصیف کنی. از همین یه فایل هم صفحه مستند تعاملی ساخته می شه، هم می تونی سرور آزمایشی و کد کلاینت تولید کنی. نتیجه اش اینه که بک اند، فرانت، موبایل و سرویس های بیرونی همه به یه منبع نگاه می کنن. دیگه لازم نیست برای اتصال سرویس ها پرسش و جواب کنی یا حدس بزنی؛ همه روی یه قرارداد مشخص جلو می رن. تو این راهنما از یه فایل خالی شروع می کنیم و می رسیم به مستندی که تیم واقعاً ازش استفاده کنه.
پیش از نوشتن فایل: سه تصمیمی که مستند رو سالم نگه می داره
خیلی از مستندهای API خیلی زود از دور خارج می شن. دلیلش معمولاً ابزار نیست، تصمیم های اولیه است. این سه تا رو قبل از نوشتن اولین خط روشن کن.
مخاطب مستند کیه؟
مستندی که برای هم تیمی بک اندت می نویسی با مستندی که برای شریک تجاری یا توسعه دهنده بیرونی می نویسی فرق داره. هم تیمی تو یه توضیح کوتاه رو می فهمه و ترجیح می ده سریع به مثال برسه. شریک بیرونی نه کد تو رو دیده، نه تو جلسه های تیم بوده. براش باید معنی هر فیلد، محدودیت ها، قالب خطاها و روش احراز هویت رو صریح بنویسی. سطح جزئیات و تعداد مثال ها رو از همین جا تعیین کن.
اول طراحی یا اول کد؟
دو روش رایج داریم:
- design-first: اول فایل OpenAPI رو می نویسی و روش توافق می کنی، بعد بک اند و فرانت موازی شروع می کنن.
- code-first: اول کد بک اند رو می نویسی و فایل از روی کد یا حاشیه نویسی ها تولید می شه.
برای تیم های کوچکی که بک اند و فرانت رو هم زمان جلو می برن، معمولاً design-first سریع تر جواب می ده. فرانت لازم نیست منتظر endpoint واقعی بمونه و بحث ها قبل از کدنویسی تموم می شن، نه بعدش. ولی اگه یه API قدیمی و بزرگ داری که مستند نداره، برای شروع code-first واقع بینانه تره. فقط یادت باشه خروجی خودکار معمولاً توضیح و مثال درست و حسابی نداره و بعد از تولید باید فایل رو دستی مرتب کنی. معیار ساده است: اگه هنوز چیزی ننوشتی، از فایل شروع کن. اگه کد داری، از کد شروع کن و فایل رو بعدش به منبع اصلی تبدیل کن.
یه منبع حقیقت
فایل OpenAPI باید توی همون مخزن Git باشه که کد توشه. نه توی Word، نه PDF، نه پیام های تلگرام و واتس اپ. وقتی فایل کنار کد باشه، تغییرش مثل هر تغییر دیگه از مسیر Pull Request رد می شه و تاریخچه داره.
فایل OpenAPI مثل نقشه فنی یه ساختمونه. برقکار، لوله کش و نقاش هر کدوم کار خودشون رو می کنن، ولی همه از یه نقشه پیروی می کنن. اگه هر کس نقشه خودش رو تو ذهنش داشته باشه، یه جایی لوله به دیوار و سیم به لوله می خوره.
گام اول: اسکلت فایل OpenAPI رو بساز
فایل پنج بخش اصلی داره:
openapi: نسخه مشخصات (specification) که ازش استفاده می کنی.info: اسم، توضیح و نسخه API.servers: نشانی سرورهایی که API روشون اجرا می شه، مثلاً اصلی و آزمایشی.paths: خود endpointها.components: قطعه های قابل استفاده مجدد، مثل اسکیماها، پاسخ های مشترک و تعریف احراز هویت.
یه نمونه کوچک با یه endpoint ساده، دریافت فهرست سفارش ها:
openapi: 3.0.3
info:
title: API فروشگاه نمونه
version: 1.0.0
description: سرویس سفارش ها برای وب سایت و اپلیکیشن موبایل
servers:
- url: https://api.example.ir/v1
description: سرور اصلی
- url: https://staging-api.example.ir/v1
description: سرور آزمایشی
paths:
/orders:
get:
operationId: listOrders
tags: [orders]
summary: فهرست سفارش های کاربر
responses:
"200":
description: فهرست سفارش ها
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Order"
components:
schemas:
Order:
type: object
properties:
id:
type: integer
status:
type: string
کدوم نسخه رو انتخاب کنم؟
دو نسخه رایج ۳.۰ و ۳.۱ هستن. ۳.۱ به JSON Schema نزدیک تره و بعضی چیزها، مثل نوع nullable، توش متفاوت نوشته می شه. ولی همه ابزارها (ویرایشگرها، تولیدکننده های کد، سرورهای mock) ۳.۱ رو به یه اندازه خوب پشتیبانی نمی کنن. قبل از انتخاب، ابزارهایی که تو پروژه ات استفاده می کنی رو با نسخه مورد نظرت امتحان کن و مستندات رسمیشون رو چک کن. اگه شک داشتی، با ۳.۰.x شروع کن که بیشتر ابزارها باهاش مشکلی ندارن.
نام گذاری که بعداً نجاتت می ده
چند عادت از همین اول به خودت بده:
- مسیرها ثابت و قابل پیش بینی باشن:
/ordersو/orders/{orderId}، نه ترکیب بی قاعده ای از اسم های فارسی و انگلیسی. operationIdبرای هر عملیات یکتا باشه، مثلlistOrdersیاcreateOrder. تولیدکننده های کد اسم تابع ها رو از همین می گیرن. اگه تکراری یا شلوغ باشه، کد کلاینت هم شلوغ می شه.- با
tagsendpointها رو دسته بندی کن (orders، payments، shipping). صفحه مستند بر اساس همین تگ ها گروه بندی می شه و پیدا کردن چیزها آسون تر می شه.

گام دوم: endpointها، پارامترها و بدنه درخواست
حالا فایل رو از اسکلت به چیزی تبدیل کن که یه آدم دیگه بتونه بدون پرسیدن از تو ازش استفاده کنه.
پارامترها: path، query و header
سه نوع پارامتر رایج داریم:
- path: بخشی از آدرس، مثل
orderIdتوی/orders/{orderId}. همیشه اجباریه. - query: بعد از علامت
?، مثلpageیاstatusبرای فیلتر و صفحه بندی. معمولاً اختیاریه. - header: مثل
Authorizationیا شناسه درخواست.
برای هر کدوم name، in، required، نوع داده و یه توضیح کوتاه بنویس:
paths:
/orders:
get:
operationId: listOrders
parameters:
- name: status
in: query
required: false
description: فیلتر براساس وضعیت سفارش
schema:
type: string
enum: [pending, paid, shipped, canceled]
- name: page
in: query
schema:
type: integer
minimum: 1
default: 1
enum خیلی کمک می کنه. فرانت دیگه لازم نیست حدس بزنه وضعیت ها چی هستن؛ لیست دقیقشون جلوی چشمشه.
اسکیما و $ref: هر مدل یک بار
مدل هایی که چند جا استفاده می شن، مثل کاربر یا سفارش، فقط یک بار توی components/schemas تعریف کن و هر جا لازم بود با $ref بهشون ارجاع بده. اگه همون مدل رو سه جا کپی کنی، یه روز فیلدی رو تو یکی اضافه می کنی و دوتای دیگه یادت می ره. اون موقع مستند دو تا واقعیت متفاوت نشون می ده.
بدنه درخواست ساخت سفارش رو ببین:
post:
operationId: createOrder
tags: [orders]
summary: ثبت سفارش جدید
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrderRequest"
example:
customerPhone: "09120000000"
items:
- productId: 1204
quantity: 2
amountRial: 4500000
callbackUrl: "https://shop.example.ir/payment/callback"
مثال هایی که به کار واقعی می خورن
نوشتن string و integer کافی نیست. مثال همون چیزیه که آدم ها اول از همه می خونن. با example یا examples داده های نزدیک به واقعیت بذار؛ مثلاً شماره موبایل ایرانی با فرمت درست، آدرس بازگشت از درگاه و مبلغ.
یه نکته مخصوص ایران: ما تو فروشگاه ها معمولاً با تومان فکر می کنیم، ولی بعضی درگاه های پرداخت مبلغ رو به ریال می خوان. این تفاوت جایی بوده که کلی باگ ازش در اومده. اسم فیلد رو شفاف بذار (amountRial نه amount) و توی description بنویس واحدش چیه. همین یه خط جلوی ده برابر یا یک دهم شدن مبلغ رو می گیره.
فرض کن فروشگاه آنلاینت باید با درگاه پرداخت، پنل پیامکی و سرویس ارسال حرف بزنه. اگه هر کدوم از این سه سرویس بیرونی قالب خطا و احراز هویت خودشون رو دارن، لایه API خودت باید یه قالب یکدست بهشون بده. اون قالب رو هم همین فایل مشخص می کنه، که گام بعدیه.
گام سوم: پاسخ ها و خطاها رو جدی بنویس
اکثر مستندها فقط پاسخ 200 رو دارن. ولی مشکل واقعی تو اتصال سرویس ها وقتی شروع می شه که یه اتفاق غیرمنتظره بیفته. مستند خوب می گه چه خطاهایی ممکنه برگرده و چه کاری باید کرد.
یه قالب یکسان برای همه خطاها
قالب خطا رو یک بار تعریف کن و همه جا استفاده کن:
components:
schemas:
Error:
type: object
required: [code, message]
properties:
code:
type: string
example: INVALID_REQUEST
message:
type: string
example: فیلد amountRial باید بزرگ تر از صفر باشد
responses:
BadRequest:
description: درخواست نامعتبر
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Unauthorized:
description: توکن نامعتبر یا منقضی
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
بعد توی هر endpoint فقط ارجاع می دی: $ref: "#/components/responses/BadRequest". برای 400، 401، 404 و 422 که تقریباً همه جا تکرار می شن، خیلی جواب می ده.
خطاهایی که از بیرون میان رو هم توضیح بده
تو اتصال به درگاه های پرداخت یه سناریوی آشنا هست: بعضی درگاه ها فقط از IPهای ثبت شده درخواست قبول می کنن. اگه IP سرورت ثبت نشده باشه، خطایی درباره نامعتبر بودن آدرس سرور برمی گرده. آدم اول فکر می کنه کد یا آدرس callback اشتباهه، ولی مشکل از کد نیست و باید IP از طرف درگاه ثبت بشه.
درس این ماجرا برای مستند چیه؟ اگه endpoint تو به یه درگاه وصله و یه خطای شناخته شده از اون طرف میاد، همون جا توی description یا توی یه مثال پاسخ بنویس که این خطا چه معنایی داره و کی باید حلش کنه. جمله ای مثل «این خطا معمولاً یعنی IP سرور ثبت نشده، با پشتیبانی درگاه هماهنگ کن» می تونه ساعت ها وقت یه توسعه دهنده رو نجات بده. بدون اون، هر تازه وارد اول کدش رو زیر و رو می کنه.
یه هشدار هم دارم: کدهای خطای درگاه ها ممکنه عوض بشن یا از درگاهی به درگاه دیگه فرق کنن. فهرست کامل کدهای بانک رو کپی نکن. فقط خطاهایی رو بنویس که خودت دیدی و به مستند رسمی درگاه لینک بده.
گام چهارم: احراز هویت رو توی فایل تعریف کن
اگه API تو توکن می خواد، همین رو توی securitySchemes بنویس تا صفحه مستند دکمه ورود توکن رو نشون بده:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
security در سطح بالای فایل یعنی پیش فرض همه endpointها محافظت شده هستن. برای endpointهای عمومی، مثل ورود یا فهرست محصولات، security: [] بذار تا مشخص باشه اونجا توکن لازم نیست.
دو تا اشتباه رایج رو رعایت نکن:
- توکن واقعی توی مثال نذار. مثال ها توی Git و صفحه مستند می مونن. مقدارهای ساختگی مثل
eyJ...exampleبذار. - همه چیز رو عمومی نکن. اگه بعضی endpointها فقط برای استفاده داخلی هستن، یا برای اونا فایل جدا بساز یا از مستند عمومی بیرونشون بذار. وجود یه endpoint داخلی توی مستندی که شریک بیرونی می بینه، یعنی نقشه ورود به یه جای حساس رو بهش دادی.
اگه سرویس های داخلی ات پشت فایروال و بدون دسترسی بیرونی هستن، همین منطق رو توی مستند هم رعایت کن. برای قاعده های پایه فایروال سرور می تونی تنظیم فایروال UFW روی سرور اوبونتو رو هم بخونی.
گام پنجم: فایل رو بررسی کن و صفحه مستند بساز
نوشتن فایل نصف کاره. نصف دیگه اینه که مطمئن بشی فایل درسته و آدم ها می تونن بخوننش.
با lint خطاها رو قبل از بقیه پیدا کن
ابزار Spectral فایل رو بر اساس یه سری قاعده بررسی می کنه: توضیح نداره، operationId تکراریه، $ref شکسته است. اجراش ساده است:
npx @stoplight/spectral-cli lint openapi.yaml
Spectral برای اجرا یه فایل قاعده می خواد. ساده ترینش یه فایل .spectral.yaml کنار فایل OpenAPI با این محتواست:
extends: ["spectral:oas"]
دلیلش روشنه: خطای فایل رو وقتی خودت پیدا کنی، ارزونه. وقتی فرانت با مستند خراب کار کنه و بعد از دو روز بفهمه، گرون تموم می شه. ابزار و نسخه هاش ممکنه عوض بشن، پس قبل از استفاده توی پروژه مستندات رسمیشون رو نگاه کن.
صفحه تعاملی با Swagger UI یا Redoc
دو انتخاب رایج داری:
- Swagger UI: صفحه ای که می تونی توش درخواست واقعی بفرستی (Try it out). برای تیم داخلی عالیه.
- Redoc: صفحه ای خوش خوان و مرتب با چیدمان سه ستونه. برای مستند عمومی و شریک ها بهتره.
اجرای سریع Swagger UI با داکر:
docker run -p 8080:8080 \
-e SWAGGER_JSON=/spec/openapi.yaml \
-v "$(pwd)":/spec \
swaggerapi/swagger-ui
ساخت یه صفحه HTML ثابت با Redoc:
npx @redocly/cli build-docs openapi.yaml -o docs/index.html
اگه هنوز داکر رو نصب نکردی، چک لیست نصب داکر روی اوبونتو مسیر امنی برای شروع می ده.
فایل های صفحه رو خودت میزبانی کن
یه نکته که تو شرایط ایران مهمه: بعضی قالب های آماده مستند، فایل های JavaScript و CSS رو از CDNهای خارجی لود می کنن. وقتی دسترسی به بعضی سرویس های بین المللی ناپایداره، صفحه مستندت هم می تونه بدون استایل یا خالی بالا بیاد، دقیقاً وقتی تیم لازمش داره. بهتره فایل های ثابت رو روی سرور خودت یا همون وب سروری بذاری که API پشتشه. درباره این شرایط بیشتر توی محدودیت اینترنت بین الملل؛ سایت ایرانی خودت را کجا محافظت کنی نوشتیم.

از مستند به کار: سرور آزمایشی، تولید کد و تست
وقتی فایل دقیق باشه، چند تا کار اضافه رو رایگان می گیری.
سرور mock برای فرانت
با ابزاری مثل Prism می تونی از روی همین فایل یه سرور آزمایشی بالا بیاری که پاسخ های مثال رو برگردونه:
npx @stoplight/prism-cli mock openapi.yaml
تیم فرانت یا موبایل دیگه منتظر آماده شدن بک اند نمی مونه. فقط مثال های فایل رو جدی بنویس. اگه مثال ها بی معنی باشن، رابط کاربری هم با داده بی معنی ساخته می شه و بعداً با داده واقعی می ریزه.
تولید کد کلاینت
ابزارهایی مثل OpenAPI Generator از روی فایل، کلاینت برای زبان های مختلف تولید می کنن. اینجاست که operationId تمیز به دردت می خوره. ولی صادقانه بگم: کد تولید شده همیشه به سلیقه تو نیست. بعضی تیم ها فقط تایپ ها و مدل ها رو تولید می کنن و منطق فراخوانی رو خودشون می نویسن. برای شروع کوچیک، همین هم کلی خطای تایپی رو حذف می کنه.
تست قرارداد
اگه بک اند چیزی برگردونه که با فایل نخونه، باید همون موقع بفهمی. چند ابزار هستن که درخواست ها رو بر اساس فایل به سرور واقعی می فرستن و پاسخ رو با اسکیما مقایسه می کنن. اینجاست که فایل از «مستند» به «قرارداد» تبدیل می شه. اگه API تو داره بزرگ می شه و می خوای این قرارداد رو از اول درست بنا کنی، طراحی و توسعه API همون کاریه که ما براش وقت می ذاریم.
مستندسازی API با OpenAPI توی روند هر انتشار
بزرگ ترین دشمن مستند، کهنه شدنه. مستندی که دو ماه به روز نشده، از نبودن مستند هم بدتره، چون آدم ها بهش اعتماد می کنن.
فایل رو توی CI بذار
سه تا کار رو خودکار کن:
- اجرای lint روی هر Pull Request. اگه فایل خطا داشت، ادغام متوقف بشه.
- ساخت صفحه مستند در هر انتشار.
- (اختیاری) اجرای تست قرارداد روی سرور آزمایشی.
اگه تیمت فرآیند انتشار خودکار نداره، همین سه قدم بهانه خوبی برای شروعشه. برای ساختن چنین مسیری می تونی از خدمات DevOps کمک بگیری.
بعد از انتشار، تنظیمات وب سرور رو هم چک کن
یه اشتباه رایج بعد از انتشار اینه که تنظیمات تازه وب سرور بارگذاری نشده و فایل های ثابت جدید خطای ۴۰۴ می دن. برای همین بارگذاری دوباره تنظیمات رو جزو مراحل ثابت هر انتشار بذار.
برای صفحه مستند هم همین قاعده صدق می کنه. اگه مسیر جدیدی مثل /docs اضافه کردی یا محل فایل های ثابت عوض شده، فقط کپی فایل کافی نیست. تنظیمات وب سرور رو اعتبارسنجی و دوباره بارگذاری کن، بعد صفحه رو از بیرون باز کن و مطمئن شو خطای ۴۰۴ نمی ده.
نسخه بندی رو از اول جدی بگیر
info.version رو دستی رها نکن. یه قاعده ساده کافیه:
- تغییر سازگار (اضافه شدن فیلد اختیاری یا endpoint جدید): نسخه جزئی بالا می ره.
- تغییر ناسازگار (حذف یه فیلد، عوض شدن نوع داده): یا نسخه اصلی بالا می ره یا مسیر جدید (
/v2) می سازی.
تغییرهای ناسازگار رو قبل از انتشار به مصرف کننده ها خبر بده. اپ موبایلی که تو مارکت منتشر شده، نمی تونه همون ساعت آپدیت بشه.
برای ساعت های اوج هم فکر کن
اگه صفحه مستندت قراره شریک ها یا تیم های بیرونی استفاده کنن، ببین از کدوم سرور و با چه منابعی سرو می شه. یه صفحه ثابت HTML معمولاً فشار زیادی نمی ده. ولی اگه Try it out رو روی سرور اصلی باز گذاشته باشی، درخواست های آزمایشی دیگران قاطی ترافیک واقعی می شه. بهتره Try it out رو فقط روی سرور آزمایشی فعال کنی.
اشتباه های رایجی که زیاد دیدیم
- فایل جدا از کد زندگی می کنه. هر کس به کد دست می زنه، فایل یادش می ره. چک لیست Pull Request رو طوری بنویس که تغییر API بدون تغییر فایل قبول نشه.
- توضیح ها خالی یا بی ارزشن. نوشتن «شناسه سفارش» برای
orderIdچیزی اضافه نمی کنه. بنویس شناسه از کجا میاد و چه فرمتی داره. - همه چیز اجباریه یا همه چیز اختیاری.
requiredرو دقیق بنویس. فیلدی که واقعاً لازم نیست رو اجباری نکن، چون کلاینت های تولید شده می شکنن. - مثال ها با اسکیما نمی خونن. مثال ها رو اعتبارسنجی کن. lint معمولاً این رو می گیره.
- مستند فقط برای حالت خوب نوشته شده. بدون خطاها، مستند نصفه است.
- کل فایل تو یه تکه است. وقتی فایل چند هزار خط شد، می تونی به چند فایل بشکنیش و با
$refبین فایل ها وصلشون کنی. ولی قبلش مطمئن شو ابزارهات این ارجاع های چندفایلی رو درست پشتیبانی می کنن.
سوالات متداول
فرق مستندسازی API با OpenAPI و یه فایل Postman چیه؟
کالکشن Postman بیشتر مجموعه ای از درخواست های نمونه است. فایل OpenAPI یه توصیف استاندارد و مستقل از ابزاره که اسکیما، خطاها و احراز هویت رو هم می گه. از OpenAPI می شه کالکشن Postman هم ساخت، ولی برعکسش معمولاً اطلاعات کمتری داره.
فایل رو با YAML بنویسم یا JSON؟
هر دو معتبرن و ابزارها هر دو رو می خونن. برای نوشتن و بازبینی دستی، YAML خواناتره و خط کمتری داره. JSON وقتی بهتره که فایل رو یه برنامه تولید می کنه. فقط توی YAML مراقب تورفتگی (indent) باش، چون یه فاصله اضافه کل ساختار رو عوض می کنه.
برای API کوچیک هم ارزش داره مستند OpenAPI بنویسم؟
معمولاً بله، به خصوص اگه بیش از یک نفر با API کار می کنه یا قراره یه اپ موبایل بهش وصل بشه. برای API با دو سه endpoint فایل کوتاهیه و نوشتنش زمان کمی می بره. اگه فقط خودت مصرف کننده ای و قرار نیست تغییرش بدی، فایده اش کمتره.
صفحه مستند رو عمومی کنم یا پشت لاگین بذارم؟
بستگی به مخاطب داره. برای یه شریک تجاری مشخص، پشت احراز هویت یا فهرست IP مجاز امن تره. API عمومی رو می تونی عمومی مستند کنی، ولی endpointها و جزئیات داخلی رو از فایل عمومی بیرون نگه دار. در هر دو حالت، توکن و داده واقعی نباید توی مثال ها باشه.
اگه فایل OpenAPI با رفتار واقعی سرور نخونه چی؟
یعنی قرارداد شکسته شده. اول ببین کدوم درسته: اگه فایل درسته، کد رو اصلاح کن. اگه کد درسته و فایل کهنه است، فایل رو اصلاح کن. برای اینکه تکرار نشه، تست قرارداد رو توی CI بذار تا اختلاف همون روز پیدا بشه.
جمع بندی: از کجا شروع کنیم؟
لازم نیست اول همه API رو مستند کنی. یه endpoint مهم رو بردار، اسکلت فایل رو بساز، پارامترها و مثال ها و خطاهای اصلی رو بنویس و lint رو اجرا کن. بعد صفحه تعاملی رو بالا بیار و به هم تیمی ها نشون بده. اگه از همون فایل کوچک تونستن کار کنن، بقیه رو کم کم اضافه کن.
سه قاعده رو فراموش نکن: فایل کنار کد توی Git بمونه، هر تغییر API با تغییر فایل همراه باشه و انتشار صفحه مستند جزو مراحل ثابت انتشار باشه. اگه جایی گیر کردی یا می خوای معماری API و مسیر انتشارش رو با یه متخصص بررسی کنی، مشاوره و معماری رو ببین.


