پاسخ API باید چه ساختاری داشته باشد
جمعبندی: اشیای خالی تا وقتی به فراداده نیاز پیدا نکنید تمیزند؛ پاکت کامل امن اما پرگو است. برای بیشتر پروژهها از وضعیت HTTP برای نتیجه و پاکت پایدار برای داده استفاده کنید.

جمعبندی: نتیجه را با کدهای وضعیت 4xx/5xx بیان کنید، payload را در { "data": ..., "meta": ... } حمل کنید و در شکست به پاکت error بروید؛ این برای APIهای داخلی کافی است و فقط پلتفرمهای عمومی با یکپارچهسازهای زیاد به JSON:API یا OpenAPI نیاز دارند.
اول بدترین گزینه را رد کنید: همیشه برگرداندن ۲۰۰ با نتیجه در فیلد code.
سه شکل
الف. شیء خالی
{ "id": 1, "name": "demo", "price": 99 }
تمیز، و معناشناسی HTTP کار را میکند (404 همان 404 است). اما لحظهای که صفحهبندی، هشدار یا trace id لازم شود، جایی برای گذاشتنشان بدون تغییر قرارداد نیست.
ب. پاکت پایدار
{
"data": { "id": 1, "name": "demo" },
"meta": { "requestId": "abc", "took": 12 }
}
payload و فراداده جدا زندگی میکنند، پس فراداده جدید هرگز data را بازشکل نمیدهد. هزینهاش یک سطح تودرتویی است.
پ. پاکت همهچیز (پرهیز کنید)
{ "code": 0, "message": "success", "data": {...} }
شکل گناه نیست؛ رویه گناه است. وضعیت ۲۰۰ برای هر نتیجه یعنی CDNها، دروازهها، قطعکنندههای مدار، سیاستهای تلاش مجدد و داشبوردها همه موفقیت میبینند. آنگاه هر هشدار به تجزیه سفارشی نیاز دارد.
توصیه
وضعیت HTTP برای نتیجه، پاکت برای payload.
{
"data": { "id": 1, "name": "demo" },
"meta": { "requestId": "req_8f2a", "took": 12 }
}
{
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order does not exist or was deleted",
"details": [{ "field": "id", "issue": "not_found" }]
},
"meta": { "requestId": "req_8f2a" }
}
وضعیت 4xx یا 5xx؛ code پایدار و ماشینخوان؛ message برای انسان؛ details برای خطاهای فیلد-level فرم.
قواعد سخت
- endpointهای فهرست باید فراداده صفحهبندی حمل کنند. بدون
totalیا cursor هیچ صفحهگردانی نیست. - فهرستهای خالی
[]برمیگردانند، هرگزnull.null.mapیک قطعی مکرر است. - مهرهای زمانی به ISO 8601 با offset. قالب مهر زمانی را ببینید.
- یک قرارداد نامگذاری.
snake_caseیاcamelCase، یک بار در مرز تبدیلشده. - پول بهصورت عدد صحیح واحد خرد یا رشته.
99.99در شناور دودویی دقیق نیست. nullرا با غایب اشتباه نگیرید.nullیا حذف فیلد را ببینید.
چه زمانی مشخصاتی را بپذیریم
- پلتفرمهای عمومی با یکپارچهسازهای زیاد: JSON:API یا OpenAPI بههمراه پاکت مشترک
- APIهای داخلی یک تیم: پاکت بالا کافی است
- قراردادهای قوی: اول Schema، ساختارها از آن تولیدشده
مشخصات بحث را کم و ورود را ارزان میکند. برای تیم پنجنفره، JSON:API معمولاً کار منفی است.
پرسشهای متداول
چگونه بین شیء خالی و پاکت انتخاب کنم؟
وقتی صفحهبندی، هشدار یا requestId لازم دارید از پاکت استفاده کنید تا meta بدون بازشکل دادن data رشد کند. شیء خالی را فقط وقتی برگردانید که فراداده نمیخواهید و میپذیرید افزودن فیلد بعداً قرارداد را تغییر میدهد.
چرا API هرگز نباید برای هر نتیجه ۲۰۰ برگرداند؟
CDNها، دروازهها، قطعکنندههای مدار، سیاستهای تلاش مجدد و داشبوردها همه وضعیت HTTP را میخوانند تا تصمیم بگیرند کش کنند، تلاش مجدد کنند یا هشدار دهند. با ۲۰۰ همهجا، شکستها را موفقیت میپندارند و هر هشدار به تجزیه سفارشی کد کسبوکار نیاز دارد.
آیا endpointهای فهرست باید فراداده صفحهبندی حمل کنند؟
بله. بدون total یا cursor هیچ صفحهگردانی نیست، و فهرستهای خالی باید [] برگردانند نه null، وگرنه فراخوانی .map فرانتاند میشکند.