Swagger چیست؟ آموزش OpenAPI و ساخت مستندات API هوش مصنوعی با FastAPI

Swagger و OpenAPI به توسعه‌دهندگان کمک می‌کنند ساختار API، ورودی‌ها، پاسخ‌ها، احراز هویت و خطاها را به‌صورت استاندارد مستند کنند. در این آموزش، تفاوت Swagger و OpenAPI را بررسی می‌کنیم و یک API واقعی تولید متن با FastAPI، Swagger UI و API درواره می‌سازیم.

Share
ALT تصویر شاخص: آموزش Swagger و OpenAPI برای مستندسازی API هوش مصنوعی با FastAPI و درواره

اگر یک API بدون مستندات در اختیار تیم فرانت‌اند، اپلیکیشن موبایل یا مشتریان قرار دهید، احتمالاً اولین پرسش‌هایی که دریافت می‌کنید این‌ها خواهند بود:

  • آدرس Endpoint چیست؟
  • درخواست باید با GET ارسال شود یا POST؟
  • بدنه درخواست چه ساختاری دارد؟
  • کدام فیلدها اجباری هستند؟
  • کلید API را در کدام Header قرار دهیم؟
  • پاسخ موفق چه شکلی است؟
  • خطاهای ۴۰۰، ۴۰۱، ۴۲۲، ۴۲۹ و ۵۰۰ چه معنایی دارند؟
  • آیا نمونه درخواست برای Python یا JavaScript وجود دارد؟

Swagger و OpenAPI برای حل همین مشکل ساخته شده‌اند. با استفاده از آن‌ها می‌توان قرارداد API را به شکلی استاندارد و قابل‌خواندن برای انسان و نرم‌افزار تعریف کرد.

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

این پروژه به‌صورت خودکار دارای Swagger UI، اعتبارسنجی ورودی، احراز هویت، مستندات خطا و فایل OpenAPI خواهد بود.

Swagger چیست؟

Swagger نام مجموعه‌ای از ابزارهای طراحی، مستندسازی، آزمایش و تولید کد برای APIها است.

برخی از ابزارهای شناخته‌شده خانواده Swagger عبارت‌اند از:

  • Swagger UI
  • Swagger Editor
  • Swagger Codegen
  • Swagger Core
  • Swagger CLI

Swagger در ابتدا نام یک Specification برای توصیف APIهای REST بود. این Specification بعداً به پروژه OpenAPI Initiative منتقل شد و نام آن به OpenAPI Specification تغییر کرد.

به همین دلیل، امروزه اصطلاح‌های Swagger و OpenAPI گاهی به‌جای یکدیگر استفاده می‌شوند؛ اما از نظر دقیق، این دو یکسان نیستند.

OpenAPI چیست؟

OpenAPI Specification یا OAS یک استاندارد برای توصیف APIهای مبتنی بر HTTP است.

یک سند OpenAPI می‌تواند مشخص کند:

  • چه Endpointهایی در API وجود دارند.
  • هر Endpoint از چه متد HTTP استفاده می‌کند.
  • پارامترهای Path و Query چیست.
  • بدنه درخواست چه ساختاری دارد.
  • پاسخ موفق چگونه است.
  • چه خطاهایی ممکن است برگردانده شوند.
  • API از چه روش احراز هویتی استفاده می‌کند.
  • آدرس محیط Production و آزمایشی چیست.
  • هر فیلد چه نوع داده و محدودیتی دارد.

OpenAPI Initiative این استاندارد را یک روش رسمی برای توصیف HTTP APIها معرفی می‌کند. چنین توصیفی می‌تواند برای مستندسازی، تولید Client، ساخت تست و اعمال استانداردهای طراحی API استفاده شود.

فایل OpenAPI معمولاً با یکی از قالب‌های زیر نوشته می‌شود:

  • YAML
  • JSON

نمونه بسیار ساده:

openapi: 3.1.0

info:
  title: AI Text API
  version: 1.0.0

paths:
  /v1/generate:
    post:
      summary: Generate text
      responses:
        "200":
          description: Successful response

این فایل به ابزارهایی مانند Swagger UI اجازه می‌دهد مستندات تعاملی API را تولید کنند.

تفاوت Swagger و OpenAPI چیست؟

اصطلاحتعریف
OpenAPIاستاندارد توصیف ساختار API
Swagger UIرابط گرافیکی برای نمایش و آزمایش OpenAPI
Swagger Editorمحیط نوشتن و اعتبارسنجی فایل OpenAPI
Swagger Codegenابزار تولید Client SDK یا Server Stub
Swaggerنام خانواده ابزارهایی که با OpenAPI کار می‌کنند

به زبان ساده، OpenAPI مانند نقشه فنی ساختمان است و Swagger UI ابزاری است که این نقشه را به شکل قابل‌فهم و تعاملی نمایش می‌دهد.

Swagger UI چیست؟

Swagger UI فایل OpenAPI را دریافت و آن را به یک صفحه مستندات تعاملی تبدیل می‌کند.

در این صفحه توسعه‌دهنده می‌تواند:

  • Endpointها را مشاهده کند.
  • Schema ورودی و خروجی را ببیند.
  • پارامترها را وارد کند.
  • کلید API را تنظیم کند.
  • با گزینه Try it out درخواست واقعی بفرستد.
  • کد وضعیت و پاسخ سرور را بررسی کند.
  • نمونه درخواست curl دریافت کند.

Swagger UI برای نمایش تعاملی تعریف‌های OpenAPI طراحی شده است.

چرا مستندسازی APIهای هوش مصنوعی مهم‌تر است؟

APIهای هوش مصنوعی معمولاً فقط چند فیلد ساده دریافت نمی‌کنند. این APIها ممکن است تنظیماتی مانند موارد زیر داشته باشند:

  • شناسه مدل
  • پیام‌های System و User
  • Temperature
  • محدودیت طول خروجی
  • ابزارهای قابل فراخوانی
  • خروجی ساختاریافته
  • ورودی تصویر یا فایل
  • Streaming
  • شناسه کاربر یا پروژه
  • Webhook
  • وضعیت اجرای غیرهم‌زمان

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

مستندات دقیق همچنین کمک می‌کند تیم‌ها تفاوت میان خطاهای ورودی، محدودیت نرخ، Timeout و خطای سرویس مدل را تشخیص دهند.

اجزای اصلی یک سند OpenAPI

بخش openapi

نسخه Specification را مشخص می‌کند:

openapi: 3.1.0

نسخه OpenAPI با نسخه نرم‌افزار یا API شما یکسان نیست. برای مثال، ممکن است سند شما از OpenAPI 3.1 استفاده کند اما نسخه تجاری API برابر 2.4.0 باشد.

بخش info

اطلاعات اصلی API در این بخش قرار می‌گیرد:

info:
  title: Darvareh AI Gateway
  version: 1.0.0
  description: API for generating Persian content

بخش servers

آدرس محیط‌های مختلف را مشخص می‌کند:

servers:
  - url: https://api.example.com
    description: Production

  - url: https://staging-api.example.com
    description: Staging

بخش paths

تمام Endpointها و عملیات آن‌ها در این قسمت تعریف می‌شوند:

paths:
  /v1/generate:
    post:
      summary: Generate Persian text

بخش components

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

components:
  schemas:
    GenerateRequest:
      type: object
      properties:
        prompt:
          type: string

بخش security

روش احراز هویت را مشخص می‌کند:

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

رویکرد Code First و Design First

برای ساخت مستندات OpenAPI دو روش اصلی وجود دارد.

روش Code First

ابتدا API را در فریم‌ورکی مانند FastAPI می‌نویسید. سپس فریم‌ورک فایل OpenAPI را از روی Routeها، مدل‌ها و Type Hintها تولید می‌کند.

این روش برای پروژه‌هایی مناسب است که:

  • تیم کوچک‌تری دارند.
  • API همراه با کد توسعه پیدا می‌کند.
  • سرعت پیاده‌سازی اهمیت دارد.
  • از FastAPI، NestJS یا Spring Boot استفاده می‌کنند.

روش Design First

ابتدا قرارداد OpenAPI نوشته می‌شود. سپس تیم‌های Backend، Frontend و Mobile بر اساس همان قرارداد توسعه را آغاز می‌کنند.

این روش برای پروژه‌هایی مناسب است که:

  • چند تیم روی یک محصول کار می‌کنند.
  • API عمومی یا سازمانی است.
  • قرارداد باید پیش از پیاده‌سازی تأیید شود.
  • چند زبان برنامه‌نویسی در پروژه استفاده می‌شود.
  • Client SDK از روی قرارداد تولید می‌شود.

در پروژه‌های بزرگ می‌توان از ترکیب هر دو روش استفاده کرد؛ اما باید فقط یک منبع نهایی حقیقت یا Source of Truth وجود داشته باشد.

پروژه عملی: ساخت API تولید متن با Swagger و درواره

در این پروژه یک API با Endpoint زیر می‌سازیم:

POST /v1/generate

این Endpoint:

  1. درخواست کاربر را دریافت می‌کند.
  2. کلید دسترسی اپلیکیشن را بررسی می‌کند.
  3. ورودی را با Pydantic اعتبارسنجی می‌کند.
  4. درخواست را به API درواره می‌فرستد.
  5. خروجی مدل را در قالب مشخص برمی‌گرداند.
  6. خطاهای متداول را به پاسخ استاندارد تبدیل می‌کند.
  7. مستندات Swagger UI را به‌صورت خودکار تولید می‌کند.

نکته مهم این است که کلید API درواره باید فقط در Backend نگهداری شود. نباید آن را داخل کد JavaScript مرورگر یا اپلیکیشن عمومی قرار دهید.

ساخت پروژه

پوشه پروژه را ایجاد کنید:

mkdir swagger-ai-api
cd swagger-ai-api

محیط مجازی پایتون را بسازید:

python -m venv .venv

فعال‌سازی در Linux و macOS:

source .venv/bin/activate

فعال‌سازی در Windows PowerShell:

.venv\Scripts\Activate.ps1

وابستگی‌ها را نصب کنید:

pip install fastapi uvicorn openai pydantic python-dotenv

تنظیم متغیرهای محیطی

فایل .env را ایجاد کنید:

DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL=YOUR_MODEL_ID
APP_API_KEY=change-this-long-random-value

کاربرد متغیرها:

  • DARVAREH_API_KEY: کلید اتصال Backend به درواره
  • DARVAREH_MODEL: شناسه مدل انتخاب‌شده
  • APP_API_KEY: کلیدی که Clientهای اپلیکیشن شما برای دسترسی به API داخلی استفاده می‌کنند

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

کد کامل FastAPI

فایل main.py را ایجاد کنید:

import os
import secrets
from typing import Annotated

from dotenv import load_dotenv
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import APIKeyHeader
from openai import (
    APIConnectionError,
    APIStatusError,
    APITimeoutError,
    AsyncOpenAI,
    RateLimitError,
)
from pydantic import BaseModel, ConfigDict, Field


load_dotenv()

DARVAREH_API_KEY = os.environ["DARVAREH_API_KEY"]
MODEL_ID = os.environ["DARVAREH_MODEL"]
APP_API_KEY = os.environ["APP_API_KEY"]

client = AsyncOpenAI(
    api_key=DARVAREH_API_KEY,
    base_url="https://api.darvareh.ir/v1",
)

app = FastAPI(
    title="Persian AI Text API",
    summary="API تولید متن فارسی با مدل‌های هوش مصنوعی",
    description=(
        "این API یک ورودی متنی دریافت می‌کند و با استفاده از "
        "مدل انتخاب‌شده در درواره پاسخ تولید می‌کند."
    ),
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_url="/openapi.json",
    contact={
        "name": "API Support",
        "url": "https://example.com/support",
    },
)

api_key_header = APIKeyHeader(
    name="X-API-Key",
    scheme_name="ApplicationApiKey",
    description="کلید دسترسی اپلیکیشن",
    auto_error=False,
)


class ErrorResponse(BaseModel):
    code: str = Field(
        description="کد قابل‌پردازش خطا",
        examples=["rate_limit_exceeded"],
    )
    message: str = Field(
        description="توضیح قابل‌نمایش خطا",
        examples=["تعداد درخواست‌ها بیش از حد مجاز است."],
    )


class GenerateRequest(BaseModel):
    model_config = ConfigDict(
        json_schema_extra={
            "examples": [
                {
                    "prompt": "یک توضیح کوتاه برای محصول قهوه عربیکا بنویس.",
                    "system_prompt": (
                        "شما یک نویسنده حرفه‌ای محتوای فروشگاهی هستید."
                    ),
                    "temperature": 0.4,
                    "max_output_tokens": 300,
                }
            ]
        }
    )

    prompt: str = Field(
        min_length=3,
        max_length=4000,
        description="دستور یا متن ورودی کاربر",
    )

    system_prompt: str = Field(
        default="شما یک دستیار فارسی دقیق و حرفه‌ای هستید.",
        min_length=3,
        max_length=2000,
        description="دستور سطح سیستم برای تعیین رفتار مدل",
    )

    temperature: float = Field(
        default=0.3,
        ge=0,
        le=2,
        description="میزان تنوع احتمالی پاسخ",
    )

    max_output_tokens: int = Field(
        default=500,
        ge=1,
        le=4000,
        description="حداکثر تعداد توکن خروجی",
    )


class GenerateResponse(BaseModel):
    model: str = Field(
        description="شناسه مدل استفاده‌شده",
        examples=["your-model-id"],
    )

    content: str = Field(
        description="متن تولیدشده توسط مدل",
        examples=["قهوه عربیکا با عطر متعادل و طعمی نرم..."],
    )

    finish_reason: str | None = Field(
        default=None,
        description="دلیل پایان تولید پاسخ",
        examples=["stop"],
    )


async def require_application_api_key(
    api_key: Annotated[str | None, Security(api_key_header)],
) -> None:
    if (
        not api_key
        or not secrets.compare_digest(api_key, APP_API_KEY)
    ):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                "code": "invalid_api_key",
                "message": "کلید دسترسی معتبر نیست.",
            },
        )


@app.get(
    "/health",
    summary="بررسی سلامت سرویس",
    tags=["System"],
)
async def health_check() -> dict[str, str]:
    return {"status": "ok"}


@app.post(
    "/v1/generate",
    response_model=GenerateResponse,
    summary="تولید متن با هوش مصنوعی",
    description=(
        "ورودی فارسی را دریافت کرده و از طریق API درواره "
        "به مدل انتخاب‌شده ارسال می‌کند."
    ),
    tags=["AI Generation"],
    dependencies=[Depends(require_application_api_key)],
    responses={
        401: {
            "model": ErrorResponse,
            "description": "کلید دسترسی نامعتبر است.",
        },
        422: {
            "description": "ساختار یا مقدار ورودی معتبر نیست.",
        },
        429: {
            "model": ErrorResponse,
            "description": "محدودیت تعداد درخواست‌ها",
        },
        502: {
            "model": ErrorResponse,
            "description": "خطا در سرویس مدل",
        },
        504: {
            "model": ErrorResponse,
            "description": "پایان مهلت پاسخ سرویس مدل",
        },
    },
)
async def generate_text(
    payload: GenerateRequest,
) -> GenerateResponse:
    try:
        completion = await client.chat.completions.create(
            model=MODEL_ID,
            messages=[
                {
                    "role": "system",
                    "content": payload.system_prompt,
                },
                {
                    "role": "user",
                    "content": payload.prompt,
                },
            ],
            temperature=payload.temperature,
            max_tokens=payload.max_output_tokens,
        )

    except RateLimitError as error:
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail={
                "code": "rate_limit_exceeded",
                "message": "ظرفیت درخواست تکمیل است؛ دوباره تلاش کنید.",
            },
        ) from error

    except APITimeoutError as error:
        raise HTTPException(
            status_code=status.HTTP_504_GATEWAY_TIMEOUT,
            detail={
                "code": "model_timeout",
                "message": "پاسخ مدل در زمان مقرر دریافت نشد.",
            },
        ) from error

    except APIConnectionError as error:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail={
                "code": "model_connection_error",
                "message": "ارتباط با سرویس مدل برقرار نشد.",
            },
        ) from error

    except APIStatusError as error:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail={
                "code": "model_api_error",
                "message": "سرویس مدل پاسخ موفقی برنگرداند.",
            },
        ) from error

    message = completion.choices[0].message.content

    if not message:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail={
                "code": "empty_model_response",
                "message": "پاسخ قابل‌استفاده‌ای از مدل دریافت نشد.",
            },
        )

    return GenerateResponse(
        model=MODEL_ID,
        content=message,
        finish_reason=completion.choices[0].finish_reason,
    )

اجرای پروژه

سرور توسعه را اجرا کنید:

uvicorn main:app --reload

پس از اجرا، آدرس‌های زیر در دسترس خواهند بود:

Swagger UI:
http://127.0.0.1:8000/docs

ReDoc:
http://127.0.0.1:8000/redoc

OpenAPI JSON:
http://127.0.0.1:8000/openapi.json

FastAPI به‌صورت پیش‌فرض Swagger UI را در /docs، رابط ReDoc را در /redoc و Schema استاندارد OpenAPI را در /openapi.json ارائه می‌کند. این مسیرها قابل تغییر یا غیرفعال‌کردن هستند.

آزمایش API در Swagger UI

مرورگر را باز کرده و وارد آدرس زیر شوید:

http://127.0.0.1:8000/docs

سپس:

  1. روی دکمه Authorize کلیک کنید.
  2. مقدار APP_API_KEY را وارد کنید.
  3. Endpoint مربوط به POST /v1/generate را باز کنید.
  4. روی Try it out کلیک کنید.
  5. بدنه درخواست را ویرایش کنید.
  6. گزینه Execute را انتخاب کنید.

نمونه درخواست:

{
  "prompt": "برای یک فروشگاه آنلاین قهوه، توضیح محصول کوتاه بنویس.",
  "system_prompt": "شما نویسنده حرفه‌ای محتوای فروشگاهی هستید.",
  "temperature": 0.4,
  "max_output_tokens": 300
}

نمونه پاسخ:

{
  "model": "your-model-id",
  "content": "قهوه عربیکای تازه‌برشت با عطر دل‌نشین، اسیدیته متعادل و طعمی نرم؛ انتخابی مناسب برای شروع یک روز پرانرژی.",
  "finish_reason": "stop"
}

Swagger UI علاوه بر پاسخ، کد وضعیت، Headerها، مدت درخواست و نمونه دستور curl را نیز نمایش می‌دهد.

ارسال درخواست با curl

همین Endpoint را می‌توان بیرون از Swagger نیز آزمایش کرد:

curl --request POST \
  --url http://127.0.0.1:8000/v1/generate \
  --header "Content-Type: application/json" \
  --header "X-API-Key: change-this-long-random-value" \
  --data '{
    "prompt": "سه عنوان برای مقاله آموزش هوش مصنوعی پیشنهاد بده.",
    "system_prompt": "پاسخ را به زبان فارسی و خلاصه بنویس.",
    "temperature": 0.5,
    "max_output_tokens": 200
  }'

ساخت OpenAPI به‌صورت دستی

FastAPI فایل OpenAPI را از روی کد تولید می‌کند، اما در روش Design First می‌توانید قرارداد را دستی بنویسید.

نمونه قرارداد خلاصه‌شده پروژه:

openapi: 3.1.0

info:
  title: Persian AI Text API
  version: 1.0.0
  description: API تولید متن فارسی با مدل‌های هوش مصنوعی

servers:
  - url: https://api.example.com

paths:
  /v1/generate:
    post:
      summary: تولید متن با هوش مصنوعی
      security:
        - ApiKeyAuth: []

      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenerateRequest"

      responses:
        "200":
          description: پاسخ با موفقیت تولید شد
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenerateResponse"

        "401":
          description: کلید دسترسی نامعتبر است
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

        "429":
          description: محدودیت تعداد درخواست‌ها
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

  schemas:
    GenerateRequest:
      type: object
      required:
        - prompt
      properties:
        prompt:
          type: string
          minLength: 3
          maxLength: 4000
          example: یک توضیح محصول کوتاه بنویس.

        system_prompt:
          type: string
          default: شما یک دستیار فارسی دقیق هستید.

        temperature:
          type: number
          minimum: 0
          maximum: 2
          default: 0.3

        max_output_tokens:
          type: integer
          minimum: 1
          maximum: 4000
          default: 500

    GenerateResponse:
      type: object
      required:
        - model
        - content
      properties:
        model:
          type: string

        content:
          type: string

        finish_reason:
          type:
            - string
            - "null"

    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string

        message:
          type: string

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

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

یک API عملی باید خطاهای مهم را نیز تعریف کند:

کد وضعیتکاربرد
400درخواست از نظر منطقی نامعتبر است
401کلید یا اطلاعات احراز هویت معتبر نیست
403کاربر اجازه اجرای عملیات را ندارد
404منبع موردنظر پیدا نشد
409درخواست با وضعیت فعلی منبع تعارض دارد
422ورودی با Schema سازگار نیست
429محدودیت نرخ درخواست رد شده است
500خطای داخلی برنامه
502سرویس بالادستی پاسخ نامعتبر داده است
504سرویس بالادستی در زمان مقرر پاسخ نداده است

بهتر است تمام خطاهای API ساختاری ثابت داشته باشند:

{
  "code": "rate_limit_exceeded",
  "message": "تعداد درخواست‌ها بیش از حد مجاز است.",
  "request_id": "req_92f1a"
}

فیلد code برای تصمیم‌گیری نرم‌افزار و message برای نمایش یا ثبت توضیح استفاده می‌شود.

مستندسازی احراز هویت

اگر API شما از API Key استفاده می‌کند، آن را به‌صورت securitySchemes تعریف کنید. نوشتن جمله «کلید را در Header بگذارید» کافی نیست.

تعریف استاندارد باعث می‌شود:

  • دکمه Authorize در Swagger UI نمایش داده شود.
  • Clientهای تولیدشده روش احراز هویت را بشناسند.
  • تست‌های خودکار Header لازم را اضافه کنند.
  • نام Header برای تمام مصرف‌کنندگان یکسان باشد.

هرگز کلید واقعی API را در مثال‌ها، فایل OpenAPI عمومی یا Repository قرار ندهید.

مستندسازی APIهای Streaming

اگر API پاسخ را به‌صورت تدریجی ارسال می‌کند، نوع محتوای پاسخ را مشخص کنید.

برای Server-Sent Events معمولاً از این Content Type استفاده می‌شود:

text/event-stream

نمونه OpenAPI:

responses:
  "200":
    description: Streaming response
    content:
      text/event-stream:
        schema:
          type: string

OpenAPI می‌تواند نوع پاسخ را توضیح دهد؛ اما Swagger UI لزوماً تمام رفتارهای Streaming را مانند یک Client واقعی نمایش نمی‌دهد. برای آزمایش دقیق Streaming بهتر است از curl، Postman یا یک Client اختصاصی استفاده شود.

مستندسازی عملیات غیرهم‌زمان

تولید ویدئو، پردازش فایل‌های بزرگ یا اجرای Workflowهای چندمرحله‌ای ممکن است چند دقیقه زمان ببرد. در این شرایط بهتر است API فوراً یک شناسه Job برگرداند:

{
  "job_id": "job_7d819",
  "status": "queued"
}

ساختار پیشنهادی Endpointها:

POST /v1/video-jobs
GET  /v1/video-jobs/{job_id}
POST /v1/video-jobs/{job_id}/cancel

در OpenAPI باید وضعیت‌های احتمالی Job نیز تعریف شوند:

status:
  type: string
  enum:
    - queued
    - processing
    - completed
    - failed
    - cancelled

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

استفاده از Swagger Editor

Swagger Editor برای نوشتن و اعتبارسنجی فایل‌های OpenAPI استفاده می‌شود.

هنگام ویرایش قرارداد می‌توانید خطاهایی مانند موارد زیر را سریع‌تر پیدا کنید:

  • تورفتگی اشتباه YAML
  • ارجاع نامعتبر با $ref
  • پاسخ بدون description
  • Schema ناقص
  • نوع داده ناسازگار
  • Security Scheme اشتباه
  • پارامتر Path تعریف‌نشده

ابزارهای رسمی Swagger شامل Editor برای طراحی API، UI برای نمایش تعاملی و Codegen برای تولید کد هستند.

تولید SDK از OpenAPI

فایل OpenAPI فقط برای مستندات نیست. می‌توان از روی آن Client SDK تولید کرد.

برای مثال، ابزار OpenAPI Generator می‌تواند Clientهایی برای زبان‌ها و پلتفرم‌های مختلف بسازد:

  • TypeScript
  • JavaScript
  • Python
  • Java
  • Kotlin
  • C#
  • Go
  • Swift
  • Dart

نمونه دستور:

openapi-generator-cli generate \
  -i openapi.yaml \
  -g typescript-fetch \
  -o clients/typescript

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

بااین‌حال، کد تولیدشده باید بازبینی و نسخه‌بندی شود. تولید SDK جایگزین طراحی درست API نیست.

استفاده از OpenAPI برای تست قرارداد

یکی دیگر از کاربردهای OpenAPI، Contract Testing است.

در این نوع تست بررسی می‌شود که:

  • Endpointهای واقعی با سند مطابقت دارند.
  • فیلدهای اجباری واقعاً اجباری هستند.
  • پاسخ‌ها از Schema تعریف‌شده پیروی می‌کنند.
  • کدهای وضعیت مستندشده به‌درستی برگردانده می‌شوند.
  • تغییر جدید باعث شکستن Clientهای قبلی نشده است.

برای مثال، اگر فیلد content در قرارداد اجباری باشد اما Backend گاهی آن را حذف کند، تست قرارداد باید این ناسازگاری را پیش از انتشار پیدا کند.

تغییرات Breaking در OpenAPI

هر تغییری در API سازگار با نسخه قبلی نیست.

نمونه تغییرات Breaking:

  • حذف یک Endpoint
  • تغییر نام فیلد
  • اجباری‌کردن یک فیلد اختیاری
  • تغییر نوع string به integer
  • حذف یکی از مقادیر Enum
  • تغییر روش احراز هویت
  • تغییر ساختار پاسخ
  • تغییر معنای یک کد وضعیت

نمونه تغییرات معمولاً سازگار:

  • اضافه‌کردن Endpoint جدید
  • اضافه‌کردن فیلد اختیاری
  • اضافه‌کردن پاسخ خطای جدید
  • اصلاح توضیحات
  • اضافه‌کردن مثال

البته سازگاری واقعی به رفتار Clientها نیز بستگی دارد. بعضی Clientها هنگام مشاهده فیلد ناشناخته خطا می‌دهند؛ بنابراین تغییرات قرارداد باید با تست مصرف‌کنندگان بررسی شود.

نسخه‌بندی API

نسخه API را می‌توان در مسیر قرار داد:

/v1/generate
/v2/generate

همچنین نسخه سند در بخش info.version ثبت می‌شود:

info:
  version: 1.2.0

این دو مقدار هدف متفاوتی دارند:

  • /v1 نسخه عمومی قرارداد و مسیر API است.
  • 1.2.0 نسخه انتشار سند یا پیاده‌سازی است.

با هر اصلاح جزئی لازم نیست مسیر /v2 ایجاد شود. نسخه اصلی جدید زمانی مناسب است که تغییرات ناسازگار و اجتناب‌ناپذیر باشند.

نکات مهم برای مستندات API هوش مصنوعی

مدل‌ها را ثابت فرض نکنید

بهتر است شناسه مدل در تنظیمات Backend یا متغیر محیطی قرار گیرد. اگر مصرف‌کننده اجازه انتخاب مدل دارد، فهرست مدل‌های مجاز را در Schema یا یک Endpoint جداگانه ارائه کنید.

هزینه و واحد مصرف را توضیح دهید

اگر کاربران بابت مصرف API هزینه پرداخت می‌کنند، مشخص کنید هزینه بر اساس کدام واحد محاسبه می‌شود:

  • توکن ورودی
  • توکن خروجی
  • تعداد تصویر
  • مدت صوت
  • مدت ویدئو
  • تعداد عملیات

محدودیت طول را ثبت کنید

حداکثر اندازه Prompt، فایل، تصویر یا خروجی باید در مستندات مشخص باشد.

مثال فارسی ارائه کنید

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

پاسخ مدل را تضمین قطعی معرفی نکنید

پاسخ مدل‌های مولد می‌تواند متغیر باشد. مستندات باید بین قرارداد فنی پاسخ و محتوای احتمالی مدل تفاوت قائل شوند.

برای مثال، می‌توان تضمین کرد فیلد content یک رشته است؛ اما نمی‌توان بدون ارزیابی و کنترل بیشتر تضمین کرد محتوای آن همیشه درست است.

Request ID اضافه کنید

یک شناسه درخواست مانند request_id برای پیگیری خطا، لاگ و پشتیبانی بسیار مفید است.

محدودیت نرخ را مستند کنید

اگر API دارای Rate Limit است، واحد محدودیت، بازه زمانی و رفتار Retry را توضیح دهید. در صورت امکان Headerهای مربوط به محدودیت و زمان تلاش مجدد را نیز مستند کنید.

آیا Swagger UI باید در Production عمومی باشد؟

پاسخ به نوع API بستگی دارد.

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

روش‌های متداول عبارت‌اند از:

  • محدودکردن دسترسی با احراز هویت
  • استفاده از شبکه داخلی
  • انتشار مستندات در Developer Portal
  • غیرفعال‌کردن Swagger UI عمومی
  • نگهداری فایل OpenAPI در Repository خصوصی
  • ارائه مستندات جداگانه برای API عمومی و داخلی

پنهان‌کردن Swagger UI به‌تنهایی یک راهکار امنیتی کامل نیست؛ Endpointهای واقعی همچنان باید احراز هویت، مجوزدهی، Rate Limit و اعتبارسنجی داشته باشند.

خطاهای رایج در مستندسازی Swagger

مستندات با کد هماهنگ نیست

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

فقط پاسخ موفق مستند شده است

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

مثال‌ها واقعی نیستند

نمونه‌هایی مانند "string" یا "example" برای توسعه‌دهنده ارزش کمی دارند. از داده‌ای نزدیک به کاربرد واقعی استفاده کنید.

Schema بیش از حد آزاد است

استفاده گسترده از object بدون تعریف Properties، مزیت اصلی OpenAPI را از بین می‌برد.

اطلاعات حساس داخل مثال قرار گرفته است

کلید API، اطلاعات کاربر، شماره تماس یا داده واقعی نباید در فایل مستندات ثبت شود.

همه Endpointها در یک گروه قرار گرفته‌اند

از Tagها برای دسته‌بندی استفاده کنید:

  • Authentication
  • Models
  • Text Generation
  • Image Generation
  • Video Generation
  • Jobs
  • Billing
  • System

توضیح فیلدها مبهم است

به‌جای «مقدار تنظیمات»، دقیقاً بنویسید فیلد چه اثری دارد، چه محدودیتی دارد و مقدار پیش‌فرض آن چیست.

چک‌لیست OpenAPI برای محیط واقعی

پیش از انتشار API بررسی کنید:

  • عنوان و نسخه API مشخص است.
  • محیط Production و Staging تعریف شده‌اند.
  • تمام Endpointها Summary و Description دارند.
  • ورودی و خروجی هر عملیات Schema دارد.
  • فیلدهای اجباری مشخص شده‌اند.
  • محدودیت طول و بازه اعداد تعریف شده است.
  • Enumها مستند شده‌اند.
  • احراز هویت در securitySchemes قرار دارد.
  • خطاهای اصلی مستند شده‌اند.
  • نمونه درخواست و پاسخ وجود دارد.
  • داده حساس در مثال‌ها نیست.
  • Tagها برای دسته‌بندی تعریف شده‌اند.
  • فایل OpenAPI در CI اعتبارسنجی می‌شود.
  • تغییرات Breaking پیش از انتشار شناسایی می‌شوند.
  • مستندات با نسخه واقعی سرویس هماهنگ هستند.
  • API Key سرویس مدل در Backend نگهداری می‌شود.

پرسش‌های متداول

Swagger چیست؟

Swagger مجموعه‌ای از ابزارها برای طراحی، نمایش، آزمایش و تولید کد از روی قرارداد API است. Swagger UI یکی از شناخته‌شده‌ترین ابزارهای این مجموعه محسوب می‌شود.

OpenAPI چیست؟

OpenAPI استانداردی برای توصیف Endpointها، ورودی‌ها، پاسخ‌ها، احراز هویت و سایر اجزای HTTP API است.

تفاوت Swagger و OpenAPI چیست؟

OpenAPI استاندارد توصیف API است، درحالی‌که Swagger نام مجموعه‌ای از ابزارهایی است که با این استاندارد کار می‌کنند.

آیا Swagger فقط برای REST API است؟

کاربرد اصلی OpenAPI و Swagger توصیف HTTP APIها، به‌ویژه APIهای REST است. برای معماری‌های رویدادمحور و Message Brokerها استانداردهایی مانند AsyncAPI نیز وجود دارند.

آیا FastAPI به Swagger نیاز دارد؟

FastAPI مستندات OpenAPI را از روی کد تولید می‌کند و برای نمایش تعاملی آن از Swagger UI استفاده می‌کند. معمولاً نیازی نیست Swagger UI را جداگانه نصب کنید.

فایل OpenAPI در FastAPI کجاست؟

به‌صورت پیش‌فرض در این آدرس قرار دارد:

/openapi.json

چگونه Swagger UI را در FastAPI باز کنیم؟

پس از اجرای برنامه، معمولاً این آدرس را باز کنید:

http://127.0.0.1:8000/docs

آیا می‌توان از OpenAPI برای ساخت SDK استفاده کرد؟

بله. ابزارهایی مانند OpenAPI Generator و Swagger Codegen می‌توانند از روی قرارداد OpenAPI برای زبان‌های مختلف Client SDK تولید کنند.

آیا Swagger برای API هوش مصنوعی مناسب است؟

بله. می‌توان ورودی مدل، تنظیمات تولید، ساختار پاسخ، خطاها، احراز هویت و عملیات Async را با OpenAPI مستند کرد. بااین‌حال، رفتار احتمالی و غیرقطعی محتوای مدل باید جدا از قرارداد فنی توضیح داده شود.

چگونه API درواره را در اپلیکیشن خود استفاده کنیم؟

کلید API درواره را در Backend نگه دارید و Client سازگار با OpenAI را با آدرس پایه زیر تنظیم کنید:

https://api.darvareh.ir/v1

سپس Endpoint داخلی خود را با Swagger و OpenAPI مستند کنید تا وب‌سایت، اپلیکیشن موبایل یا سایر سرویس‌ها بدون دسترسی مستقیم به کلید اصلی، از قابلیت هوش مصنوعی استفاده کنند.

جمع‌بندی

Swagger و OpenAPI فقط ابزارهایی برای ساخت یک صفحه مستندات زیبا نیستند. آن‌ها قرارداد میان Backend، Frontend، اپلیکیشن موبایل، تیم تست و مصرف‌کنندگان خارجی API را تعریف می‌کنند.

در این آموزش یاد گرفتیم چگونه:

  1. تفاوت Swagger و OpenAPI را تشخیص دهیم.
  2. ساختار اصلی یک سند OpenAPI را تعریف کنیم.
  3. با FastAPI مستندات Swagger خودکار بسازیم.
  4. ورودی و خروجی API هوش مصنوعی را اعتبارسنجی کنیم.
  5. احراز هویت API Key را در Swagger UI نمایش دهیم.
  6. خطاهای سرویس مدل را مستند کنیم.
  7. Backend را به API سازگار با OpenAI درواره متصل کنیم.
  8. قرارداد OpenAPI را برای تولید SDK و تست استفاده کنیم.
  9. تغییرات Breaking را پیش از انتشار شناسایی کنیم.

برای شروع، می‌توانید یک Endpoint محدود مانند تولید متن، خلاصه‌سازی یا طبقه‌بندی پیام بسازید. سپس Schema ورودی، پاسخ موفق، پاسخ خطا و احراز هویت آن را به‌طور کامل مستند کنید.

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

مقالات مرتبط

منابع

این مقاله صرفاً با هدف آموزش و اطلاع‌رسانی تهیه شده است. پیش از استفاده عملی، مستندات رسمی سرویس‌ها و صفحه سلب مسئولیت را مطالعه کنید.

Read more