Blogger JSON API: نکات عملکرد

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

فشرده‌سازی با استفاده از gzip

یک راه آسان و راحت برای کاهش پهنای باند مورد نیاز برای هر درخواست، فعال کردن فشرده‌سازی gzip است. اگرچه این کار به زمان اضافی CPU برای خارج کردن نتایج از حالت فشرده نیاز دارد، اما معمولاً با توجه به هزینه‌های شبکه، ارزش انجام آن را دارد.

برای دریافت پاسخی که با gzip کدگذاری شده است، باید دو کار انجام دهید: یک هدر Accept-Encoding تنظیم کنید و عامل کاربر خود را طوری تغییر دهید که شامل رشته gzip باشد. در اینجا مثالی از هدرهای HTTP که به درستی شکل گرفته‌اند برای فعال کردن فشرده‌سازی gzip آورده شده است:

Accept-Encoding: gzip
User-Agent: my program (gzip)

کار با منابع جزئی

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

دو نوع درخواست جزئی وجود دارد:

  • پاسخ جزئی : درخواستی که در آن مشخص می‌کنید کدام فیلدها در پاسخ گنجانده شوند (از پارامتر درخواست fields استفاده کنید).
  • پچ : یک درخواست به‌روزرسانی که در آن فقط فیلدهایی را که می‌خواهید تغییر دهید ارسال می‌کنید (از فعل PATCH HTTP استفاده کنید).

جزئیات بیشتر در مورد درخواست‌های جزئی در بخش‌های بعدی ارائه شده است.

پاسخ جزئی

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

برای درخواست پاسخ جزئی، از پارامتر درخواست fields برای مشخص کردن فیلدهایی که می‌خواهید برگردانده شوند استفاده کنید. می‌توانید از این پارامتر با هر درخواستی که داده‌های پاسخ را برمی‌گرداند، استفاده کنید.

توجه داشته باشید که پارامتر fields فقط بر داده‌های پاسخ تأثیر می‌گذارد؛ بر داده‌هایی که باید ارسال کنید، در صورت وجود، تأثیری ندارد. برای کاهش میزان داده‌هایی که هنگام تغییر منابع ارسال می‌کنید، از درخواست patch استفاده کنید.

مثال

مثال زیر استفاده از پارامتر fields را با یک API عمومی (تخیلی) "Demo" نشان می‌دهد.

درخواست ساده: این درخواست HTTP GET پارامتر fields را حذف کرده و منبع کامل را برمی‌گرداند.

https://www.googleapis.com/demo/v1

پاسخ کامل منبع: داده‌های کامل منبع شامل فیلدهای زیر به همراه بسیاری دیگر است که به دلیل اختصار حذف شده‌اند.

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

درخواست برای پاسخ جزئی: درخواست زیر برای همین منبع از پارامتر fields برای کاهش قابل توجه میزان داده‌های برگشتی استفاده می‌کند.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

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

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

توجه داشته باشید که پاسخ یک شیء JSON است که فقط شامل فیلدهای انتخاب شده و اشیاء والد محصور کننده آنها می‌شود.

جزئیات مربوط به نحوه قالب‌بندی پارامتر fields در ادامه پوشش داده شده است، و پس از آن جزئیات بیشتری در مورد آنچه دقیقاً در پاسخ بازگردانده می‌شود، ارائه شده است.

خلاصه سینتکس پارامتر فیلدها

قالب مقدار پارامتر درخواست fields تا حدودی مبتنی بر سینتکس XPath است. سینتکس پشتیبانی شده در زیر خلاصه شده است و مثال‌های اضافی در بخش بعدی ارائه شده است.

  • برای انتخاب چندین فیلد، از یک لیست جدا شده با کاما استفاده کنید.
  • a/b برای انتخاب فیلد b که درون فیلد a قرار دارد استفاده کنید؛ a/b/c برای انتخاب فیلد c که درون b قرار دارد استفاده کنید.

    استثنا: برای پاسخ‌های API که از پوشش‌های "data" استفاده می‌کنند، که در آن پاسخ درون یک شیء data که شبیه data: { ... } است، قرار می‌گیرد، " data " را در مشخصات fields وارد نکنید. وارد کردن شیء داده با مشخصات فیلدهایی مانند data/a/b باعث خطا می‌شود. در عوض، فقط از مشخصات fields مانند a/b استفاده کنید.

  • با قرار دادن عبارات درون پرانتز " ( ) " از یک زیر-انتخابگر برای درخواست مجموعه‌ای از زیر-فیلدهای خاص از آرایه‌ها یا اشیاء استفاده کنید.

    برای مثال: fields=items(id,author/email) فقط شناسه آیتم و ایمیل نویسنده را برای هر عنصر در آرایه items برمی‌گرداند. همچنین می‌توانید یک زیرفیلد مشخص کنید، که در آن fields=items(id) معادل fields=items/id است.

  • در صورت نیاز، از کاراکترهای عمومی (wildcards) در انتخاب فیلدها استفاده کنید.

    برای مثال: fields=items/pagemap/* تمام اشیاء موجود در یک نقشه صفحه را انتخاب می‌کند.

مثال‌های بیشتر از استفاده از پارامتر fields

مثال‌های زیر شامل توضیحاتی در مورد چگونگی تأثیر مقدار پارامتر fields بر پاسخ است.

توجه: همانند تمام مقادیر پارامترهای پرس‌وجو، مقدار پارامتر fields باید به صورت URL کدگذاری شود. برای خوانایی بهتر، مثال‌های این سند از کدگذاری صرف نظر کرده‌اند.

فیلدهایی را که می‌خواهید برگردانده شوند، شناسایی کنید یا انتخاب‌های فیلدی انجام دهید.
مقدار پارامتر درخواست fields ، فهرستی از فیلدها است که با کاما از هم جدا شده‌اند و هر فیلد نسبت به ریشه پاسخ مشخص می‌شود. بنابراین، اگر شما در حال انجام یک عملیات فهرست‌سازی هستید، پاسخ یک مجموعه است و عموماً شامل آرایه‌ای از منابع است. اگر در حال انجام عملیاتی هستید که یک منبع واحد را برمی‌گرداند، فیلدها نسبت به آن منبع مشخص می‌شوند. اگر فیلدی که انتخاب می‌کنید (یا بخشی از) یک آرایه باشد، سرور بخش انتخاب شده از تمام عناصر موجود در آرایه را برمی‌گرداند.

در اینجا چند مثال در سطح مجموعه آورده شده است:
مثال‌ها اثر
items تمام عناصر موجود در آرایه items، شامل تمام فیلدهای هر عنصر، اما بدون فیلدهای دیگر را برمی‌گرداند.
etag,items هم فیلد etag و هم تمام عناصر موجود در آرایه items را برمی‌گرداند.
items/title فقط فیلد title را برای همه عناصر موجود در آرایه items برمی‌گرداند.

هر زمان که یک فیلد تو در تو برگردانده شود، پاسخ شامل اشیاء والدِ در برگیرنده آن نیز می‌شود. فیلدهای والد شامل هیچ فیلد فرزند دیگری نمی‌شوند، مگر اینکه آنها نیز به صراحت انتخاب شوند.
context/facets/label فقط فیلد label را برای همه اعضای آرایه facets برمی‌گرداند، که خود زیر شیء context قرار دارد.
items/pagemap/*/title برای هر عنصر در آرایه items، فقط فیلد title (در صورت وجود) تمام اشیاء فرزند pagemap برمی‌گرداند.

در اینجا چند مثال در سطح منابع آورده شده است:
مثال‌ها اثر
title فیلد title منبع درخواستی را برمی‌گرداند.
author/uri زیرفیلد uri مربوط به شیء author در منبع درخواستی را برمی‌گرداند.
links/*/href
فیلد href تمام اشیاء فرزند links را برمی‌گرداند.
فقط بخش‌هایی از فیلدهای خاص را با استفاده از زیرگزینه‌ها درخواست کنید.
به طور پیش‌فرض، اگر درخواست شما فیلدهای خاصی را مشخص کند، سرور اشیاء یا عناصر آرایه را به طور کامل برمی‌گرداند. می‌توانید پاسخی را مشخص کنید که فقط شامل زیرفیلدهای خاصی باشد. این کار را با استفاده از سینتکس زیر-انتخاب " ( ) " انجام می‌دهید، مانند مثال زیر.
مثال اثر
items(title,author/uri) فقط مقادیر title و uri نویسنده را برای هر عنصر در آرایه items برمی‌گرداند.

مدیریت پاسخ‌های جزئی

پس از اینکه سرور یک درخواست معتبر که شامل پارامتر جستجوی fields است را پردازش می‌کند، یک کد وضعیت HTTP 200 OK را به همراه داده‌های درخواستی ارسال می‌کند. اگر پارامتر جستجوی fields دارای خطا باشد یا به هر دلیلی نامعتبر باشد، سرور یک کد وضعیت HTTP 400 Bad Request را به همراه یک پیام خطا که به کاربر می‌گوید چه مشکلی در انتخاب فیلدهای او وجود دارد، برمی‌گرداند (برای مثال، "Invalid field selection a/b" ).

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

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

پاسخ جزئی به این شکل است:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

نکته: برای APIهایی که از پارامترهای پرس‌وجو برای صفحه‌بندی داده‌ها پشتیبانی می‌کنند (مثلاً maxResults و nextPageToken )، از این پارامترها برای کاهش نتایج هر پرس‌وجو به اندازه‌ای قابل مدیریت استفاده کنید. در غیر این صورت، ممکن است افزایش عملکرد ممکن با پاسخ جزئی محقق نشود.

پچ (به‌روزرسانی جزئی)

همچنین می‌توانید هنگام تغییر منابع از ارسال داده‌های غیرضروری خودداری کنید. برای ارسال داده‌های به‌روزرسانی‌شده فقط برای فیلدهای خاصی که تغییر می‌دهید، از فعل HTTP PATCH استفاده کنید. معانی وصله شرح داده شده در این سند متفاوت (و ساده‌تر) از پیاده‌سازی قدیمی‌تر GData از به‌روزرسانی جزئی است.

مثال کوتاه زیر نشان می‌دهد که چگونه استفاده از patch داده‌هایی را که برای ایجاد یک به‌روزرسانی کوچک باید ارسال کنید، به حداقل می‌رساند.

مثال

این مثال یک درخواست وصله ساده را نشان می‌دهد که فقط عنوان یک منبع API عمومی (تخیلی) "Demo" را به‌روزرسانی می‌کند. این منبع همچنین دارای یک نظر، مجموعه‌ای از ویژگی‌ها، وضعیت و بسیاری از فیلدهای دیگر است، اما این درخواست فقط فیلد title ارسال می‌کند، زیرا تنها فیلدی است که تغییر می‌کند:

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

پاسخ:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

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

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

معناشناسی درخواست وصله

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

  • افزودن: برای افزودن فیلدی که از قبل وجود ندارد، فیلد جدید و مقدار آن را مشخص کنید.
  • تغییر: برای تغییر مقدار یک فیلد موجود، فیلد را مشخص کرده و مقدار جدید را به آن اختصاص دهید.
  • حذف: برای حذف یک فیلد، فیلد را مشخص کرده و آن را روی null تنظیم کنید. برای مثال، "comment": null . همچنین می‌توانید کل یک شیء (اگر قابل تغییر باشد) را با تنظیم آن روی null حذف کنید. اگر از کتابخانه کلاینت API جاوا استفاده می‌کنید، به جای آن Data.NULL_STRING استفاده کنید؛ برای جزئیات بیشتر، به JSON null مراجعه کنید.

نکته‌ای در مورد آرایه‌ها: درخواست‌های وصله که حاوی آرایه هستند، آرایه موجود را با آرایه‌ای که شما ارائه می‌دهید جایگزین می‌کنند. شما نمی‌توانید آیتم‌های یک آرایه را به صورت تدریجی تغییر دهید، اضافه یا حذف کنید.

استفاده از پچ در چرخه خواندن-تغییر-نوشتن

شروع با بازیابی یک پاسخ جزئی با داده‌هایی که می‌خواهید تغییر دهید، می‌تواند یک تمرین مفید باشد. این امر به ویژه برای منابعی که از ETag ها استفاده می‌کنند، مهم است، زیرا برای به‌روزرسانی موفقیت‌آمیز منبع، باید مقدار ETag فعلی را در هدر HTTP If-Match ارائه دهید. پس از دریافت داده‌ها، می‌توانید مقادیری را که می‌خواهید تغییر دهید تغییر دهید و نمایش جزئی اصلاح‌شده را با یک درخواست وصله ارسال کنید. در اینجا مثالی آورده شده است که فرض می‌کند منبع Demo از ETag ها استفاده می‌کند:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

این پاسخ جزئی است:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

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

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

سرور با کد وضعیت HTTP 200 OK و نمایش جزئی منبع به‌روزرسانی‌شده پاسخ می‌دهد:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

ساخت مستقیم یک درخواست پچ

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

نکته: می‌توانید از هدر HTTP با "If-Match: *" برای اعمال اجباری پچ در هنگام استفاده از ETagها استفاده کنید. اگر این کار را انجام دهید، نیازی به خواندن قبل از نوشتن ندارید.

با این حال، برای موقعیت‌های دیگر، می‌توانید درخواست وصله را مستقیماً و بدون بازیابی اولیه داده‌های موجود ایجاد کنید. برای مثال، می‌توانید به راحتی یک درخواست وصله تنظیم کنید که یک فیلد را به مقدار جدید به‌روزرسانی کند یا یک فیلد جدید اضافه کند. در اینجا مثالی آورده شده است:

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

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

مدیریت پاسخ به یک وصله

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

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

اگر درخواست وصله منجر به وضعیت منبع جدیدی شود که از نظر نحوی یا معنایی نامعتبر باشد، سرور کد وضعیت HTTP با کد 400 Bad Request یا 422 Unprocessable Entity را برمی‌گرداند و وضعیت منبع بدون تغییر باقی می‌ماند. برای مثال، اگر سعی کنید مقدار یک فیلد الزامی را حذف کنید، سرور خطایی را برمی‌گرداند.

نمادگذاری جایگزین زمانی که فعل PATCH HTTP پشتیبانی نمی‌شود

اگر فایروال شما درخواست‌های HTTP PATCH را مجاز نمی‌داند، یک درخواست HTTP POST ارسال کنید و هدر override را مطابق شکل زیر روی PATCH تنظیم کنید:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

تفاوت بین پچ و آپدیت

در عمل، وقتی برای یک درخواست به‌روزرسانی که از فعل HTTP PUT استفاده می‌کند، داده‌ها را ارسال می‌کنید، فقط باید فیلدهایی را ارسال کنید که اجباری یا اختیاری هستند؛ اگر مقادیری را برای فیلدهایی که توسط سرور تنظیم شده‌اند ارسال کنید، آنها نادیده گرفته می‌شوند. اگرچه این ممکن است راه دیگری برای انجام یک به‌روزرسانی جزئی به نظر برسد، اما این رویکرد محدودیت‌هایی دارد. در به‌روزرسانی‌هایی که از فعل HTTP PUT استفاده می‌کنند، اگر پارامترهای اجباری را ارائه ندهید، درخواست با شکست مواجه می‌شود و اگر پارامترهای اختیاری را ارائه ندهید، داده‌های تنظیم‌شده قبلی پاک می‌شوند.

به همین دلیل استفاده از patch بسیار امن‌تر است. شما فقط داده‌های مربوط به فیلدهایی را که می‌خواهید تغییر دهید، ارائه می‌دهید؛ فیلدهایی که حذف می‌کنید پاک نمی‌شوند. تنها استثنا برای این قانون در مورد عناصر یا آرایه‌های تکراری رخ می‌دهد: اگر همه آنها را حذف کنید، آنها همانطور که هستند باقی می‌مانند؛ اگر هر یک از آنها را ارائه دهید، کل مجموعه با مجموعه‌ای که شما ارائه می‌دهید جایگزین می‌شود.