برچسب: JSON

  • هشت اصل برای ساخت REST API حرفه‌ای و استاندارد

    هشت اصل برای ساخت REST API حرفه‌ای و استاندارد

    REST API یکی از پایه‌های اصلی توسعه سرویس‌ها و نرم‌افزارهای مدرن هستند، اما «RESTful بودن» تنها به استفاده از JSON یا پروتکل HTTP محدود نمی‌شود. REST در واقع یک طیف است؛ طیفی که بهترین روش توصیف آن مدل بلوغ ریچاردسون (Richardson Maturity Model – RMM) است.

    این مدل چهار سطح دارد:

    • سطح صفر – باتلاق (The Swamp): استفاده از HTTP صرفاً به‌عنوان سیستم انتقال RPC. نمونه‌اش یک مسیر واحد مانند /api که همه درخواست‌ها با POST ارسال می‌شوند.
    • سطح یک – منابع (Resources): ایجاد چند URI مستقل مثل /users یا /orders به‌جای یک نقطه ورود.
    • سطح دو – استفاده از افعال HTTP: به‌کارگیری دقیق متدهایی مثل GET، POST، PUT، DELETE همراه با کدهای وضعیت استاندارد.
    • سطح سه – اَبَررسانه یا HATEOAS: نقطه طلایی REST؛ جایی که API در پاسخ خود لینک‌ها و مسیرهای بعدی را معرفی می‌کند و کلاینت بدون وابستگی به URLهای ثابت می‌تواند سرویس را پیمایش کند.

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

    ۱. طراحی API را «پیش از کدنویسی» آغاز کنید (API First)

    قبل از نوشتن هر خط کد، قرارداد API را طراحی کنید. ابزارهایی مثل OpenAPI (Swagger) به شما امکان می‌دهند ساختار مسیرها، مدل درخواست و پاسخ و الگوهای خطا را از ابتدا مشخص کنید.

    رویکرد API First مزایای مهمی دارد:

    • تجربه مصرف‌کننده API بهبود می‌یابد.
    • یک سند زنده برای تیم توسعه ایجاد می‌شود.
    • تیم‌های فرانت‌اند و بک‌اند می‌توانند هم‌زمان کار خود را آغاز کنند.
    • از ابتدا به یکپارچگی و سازگاری در سراسر سیستم می‌رسید.

    این مرحله پایه‌ای‌ترین و مهم‌ترین گام برای ساخت یک API حرفه‌ای است.

    ۲. از «اسم» برای منابع استفاده کنید (مطابق RMM سطح ۱)

    آدرس‌های API باید معرف «منابع» باشند، نه «عملیات». عملیات را متد HTTP تعیین می‌کند.

    نمونه اشتباه (استفاده از فعل در URL):

    POST /api/createUser
    GET /api/getHabits
    

    نمونه درست (استفاده از اسم و حالت جمع):

    POST /api/users
    GET /api/habits
    

    بهترین شیوه این است که برای مجموعه از اسم جمع استفاده کنید؛ این کار الگوی استانداردی مانند: GET /habits/{id} را برای دریافت یک مورد خاص بسیار تمیز و قابل‌پیش‌بینی می‌کند.

    ۳. ساختار URL را ساده نگه دارید (از تو در تو شدن بپرهیزید)

    URLهای بیش‌ازحد تو در تو خوانایی API را کم و نگهداری آن را دشوار می‌کند.

    نمونه پیچیده (غیرمطلوب):

    /users/{userId}/habits/{habitId}/entries
    

    در چنین طراحی اگر بخواهید همه رکوردهای یک عادت را صرف‌نظر از کاربر دریافت کنید، دچار محدودیت می‌شوید.

    نسخه بهتر، طراحی تخت (Flat) است:

    نسخه مطلوب:

    /entries?habitId={habitId}
    

    قاعده کلی: اگر بیش از یک سطح تو در تو می‌سازید (/resource/{id}/sub-resource)، احتمالاً باید در طراحی خود تجدیدنظر کنید.

    ۴. از متدهای HTTP به‌درستی استفاده کنید (RMM سطح ۲)

    هر متد HTTP یک نقش دارد:

    • GET: دریافت یک منبع یا مجموعه
    • POST: ایجاد منبع جدید
    • PUT: جایگزینی کامل یک منبع
    • PATCH: به‌روزرسانی بخشی از منبع
    • DELETE: حذف منبع

    استفاده صحیح و یکپارچه از این متدها هسته اصلی یک REST API سطح ۲ محسوب می‌شود.

    ۵. کدهای وضعیت HTTP را دقیق و معنادار برگردانید

    همه‌چیز ۲۰۰ OK نیست! وضعیت پاسخ یک بخش مهم از قرارداد API است.

    موارد موفق (۲xx):

    • 200 OK: موفقیت در GET
    • 201 Created: منبع جدید ایجاد شده؛ پاسخ باید Location Header داشته باشد
    • 204 No Content: عملیات موفق است اما بدنه پاسخ لازم نیست (مثلاً DELETE)

    خطای سمت کاربر (۴xx):

    • 400 Bad Request: ورودی نامعتبر یا خطای منطقی
    • 401 Unauthorized: کاربر احراز نشده
    • 403 Forbidden: کاربر دسترسی ندارد
    • 404 Not Found: منبع موجود نیست

    خطای سمت سرور (۵xx):

    • 500 Internal Server Error: خطایی در سمت سرور رخ داده است

    ۶. خطاها را استاندارد کنید (RFC 7807)

    یکی از الزامات API حرفه‌ای این است که ساختار خطا همیشه ثابت باشد. از فرمت استاندارد Problem Details (RFC 7807) استفاده کنید. این مدل شامل:

    • type: لینک مستندات خطا
    • title: توضیح کوتاه
    • status: همان کد وضعیت HTTP
    • detail: توضیح دقیق‌تر
    • instance: مسیر مربوط به خطا

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

    ۷. از Envelope، صفحه‌بندی و Hypermedia استفاده کنید (حرکت به سمت RMM سطح ۳)

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

    ۱) Envelope

    پاسخ‌های مجموعه‌ای (Collection) را در یک ساختار مشخص قرار دهید. مثلاً:

    {
    	"data": [
    		{ "id": 1, "name": "Entry 1" }
    	]
    }
    

    ۲) Pagination

    در مجموعه‌هایی با داده زیاد، حتماً صفحه‌بندی استاندارد ارائه کنید.

    {
      "items": [...],
      "total": 120,
      "page": 1,
      "pageSize": 10
    }
    

    به کلاینت بگویید قدم بعد چیست؛ مثلاً:

    "_links": {
    "self": { "href": "/users?page=1" },
    "next": { "href": "/users?page=2" }
    }
    

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

    ۸. عمل‌گرا و سازگار باشید

    مهم‌ترین قانون در طراحی API فقط یک چیز است: سازگاری.

    • اگر از نام جمع استفاده می‌کنید، در تمام API این کار را انجام دهید.
    • اگر برای خطاهای اعتبارسنجی از وضعیت 400 استفاده می‌کنید، آن را در تمام بخش‌ها رعایت کنید.

    در کنار سازگاری، عمل‌گرا بودن نیز اهمیت دارد. خیلی از منابع توصیه می‌کنند که «REST واقعی یعنی سطح ۳ مدل ریچاردسون (Hypermedia)». اما واقعیت این است که سطح ۳ برای بسیاری از سیستم‌ها پیچیدگی اضافه ایجاد می‌کند، هم برای سرور و هم برای کلاینت.

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

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

    یک مثال ساده برای جمع‌بندی

    فرض کنید در حال توسعه یک API برای یک «اپلیکیشن ردیاب عادت‌ها (Habit Tracker)» هستید. در نمونه زیر (بر اساس ASP.NET Core)، می‌توان دید که چگونه اصول استاندارد REST در عمل اجرا می‌شوند:

    ۱. API First

    با استفاده از attributes مثل [ProducesResponseType] نوع خروجی‌ها و خطاها مشخص می‌شود و مستقیماً وارد مستندات OpenAPI می‌گردد.

    ۲. نام‌ها و افعال درست

    مسیرها باید اسم جمع باشند، مثل: [Route("entries")]
    و متدها باید مبتنی بر افعال HTTP باشند: [HttpGet], [HttpPost] و…

    ۳. کدهای وضعیت استاندارد

    • ایجاد رکورد جدید: وضعیت 201 Created همراه با Location Header
    • دریافت یک آیتم: موفقیت 200 OK یا درصورت نبودن رکورد: 404 Not Found

    ۴. بسته‌بندی (Envelope) و صفحه‌بندی

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

    ۵. مدیریت خطا بر اساس استاندارد RFC 7807

    هر خطای 4xx یا 5xx به‌صورت خودکار در قالب application/problem+json بازگردانده می‌شود.

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

    جمع‌بندی نهایی

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

    چه بخواهید به سطح کامل Hypermedia برسید و چه یک API سطح ۲ با ساختاری دقیق و سازگار بسازید، چیزی که API شما را «حرفه‌ای» می‌کند این موارد است:

    • پیروی از اصول استاندارد
    • سازگاری در تمام بخش‌ها
    • طراحی به‌صورت API First
    • مدیریت درست خطاها
    • ساده‌سازی مسیرها و دولت‌های درخواست
    • و همیشه، نگاه عمل‌گرا

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

  • JSON یا TOON، آغاز عصری جدید برای ورودی‌های ساختاریافته؟

    JSON یا TOON، آغاز عصری جدید برای ورودی‌های ساختاریافته؟

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

    هنگامی که با مدل‌های زبان بزرگ (LLM) کار می‌کنیم، خروجی‌های ساختاریافته به یک استاندارد تبدیل شده‌اند. شما می‌توانید از هوش مصنوعی بخواهید که در قالب مشخصی، مثلاً JSON، پاسخ دهد. با تعریف یک اسکیمای مدل و توضیح دقیق معنای هر فیلد، مدل سعی می‌کند خروجی را «تا حد ممکن دقیق» تولید کند. این کار پردازش نتایج AI را آسان‌تر از همیشه کرده است.

    اما با وجود اینکه می‌توانیم خروجی‌ها را مرتب و ساختاریافته کنیم، اکثر ما هنوز حجم زیادی از داده‌ها در قالب JSON، YAML یا حتی متن ساده را مستقیماً وارد پرامپت می‌کنیم. این کار نه تنها کند و پرهزینه است، بلکه از نظر تعداد توکن‌ها نیز بهینه نیست. بنابراین طبیعی بود که یک فرمت جدید برای حل این مشکل ظاهر شود و اینجاست که TOON وارد می‌شود

    TOON نسخه کم‌حجم و بهینه JSON

    TOON یک فرمت فایل جدید است که بین JSON و CSV قرار می‌گیرد. این فرمت همچنان قابل خواندن توسط انسان است، اما برای مدل‌های LLM و بهره‌وری توکن بهینه‌سازی شده است. سازندگان TOON ادعا می‌کنند که می‌تواند تعداد توکن‌ها را ۳۰ تا ۶۰ درصد کاهش دهد، که با توجه به نحوه قیمت‌گذاری توکن‌ها، صرفه‌جویی مالی قابل توجهی ایجاد می‌کند.

    ویژگی‌های TOON:

    • بهینه برای توکن‌ها: معمولاً ۳۰–۶۰٪ توکن کمتر نسبت به JSON
    • سازگار با LLM: طول‌ها و فیلدها به صورت واضح تعریف شده‌اند و امکان اعتبارسنجی فراهم است
    • سینتکس مینیمال: حذف علائم اضافی مثل آکولاد، کروشه و اکثر علامت‌های نقل‌قول
    • ساختار مبتنی بر تورفتگی: مانند YAML، از فاصله برای تعیین ساختار استفاده می‌کند
    • آرایه‌های جدولی: کلیدها یک بار تعریف می‌شوند و داده‌ها به صورت ردیف اضافه می‌شوند

    مثال:

    JSON

    [
      {"id": 1, "name": "Alice", "department": "Engineering", "salary": 120000},
      {"id": 2, "name": "Bob", "department": "Marketing", "salary": 95000},
      {"id": 3, "name": "Charlie", "department": "Engineering", "salary": 110000}
    ]

    TOON

    [3]{Id,Name,Department,Salary}:
    1,Alice,Engineering,120000
    2,Bob,Marketing,95000
    3,Charlie,Engineering,110000

    اگر دقیق نگاه کنید، TOON شبیه یک ملاقات بین YAML و CSV است که تصمیم گرفته‌اند یک فرزند ساختاریافته با هم داشته باشند!

    چرا باید TOON برای ما اهمیت داشته باشد؟

    اگر شما هر نوع سیستمی می‌سازید که به طور مرتب داده‌های ساختاریافته را به LLM می‌دهد، مثل چت‌بات‌ها، تولید کد با کمک AI یا گردش کار چندمرحله‌ای، TOON می‌تواند اندازه پرامپت را به شکل چشمگیری کاهش دهد.

    موضوع فقط صرفه‌جویی مالی نیست (گرچه کاهش ۵۰٪ مصرف توکن واقعاً قابل توجه است)، بلکه سرعت پردازش هم مهم است. هر چه تعداد توکن‌ها کمتر باشد، زمان پاسخ‌دهی سریع‌تر و تاخیر کمتر خواهد بود، به ویژه در سیستم‌های بلادرنگ یا هنگام استفاده از APIهای جریان داده.

    و نکته جذاب دیگر: TOON در حال حاضر برای چندین زبان برنامه‌نویسی موجود است:

    ارزیابی در دنیای واقعی

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

    نتایج:

    نوعتوکن پرامپتتوکن تکمیلزمان
    JSON13443475۰۰:۰۰:۲۸
    TOON5892928۰۰:۰۰:۲۳

    این یعنی کاهش حدود ۵۶٪ در توکن‌های پرامپت و بهبود ۵ ثانیه‌ای در سرعت، با همان کیفیت خروجی مدل. TOON نه تنها روی کاغذ خوب به نظر می‌رسد، بلکه واقعاً سریع‌تر، ارزان‌تر و قابل خواندن‌تر است.

    جمع‌بندی

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

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