مقاربات لتصميم RESTful API. أنواع طلبات HTTP وفلسفة REST أمثلة لواجهة برمجة التطبيقات المريحة

05.01.2024 مشغلي الهاتف المحمول

سأشارك في هذه المقالة تجربتي في تصميم واجهة برمجة تطبيقات RESTful - باستخدام أمثلة محددة سأوضح كيفية إنشاء خدمات بسيطة على الأقل بشكل جميل. سنتحدث أيضًا عن ماهية واجهة برمجة التطبيقات (API) وسبب الحاجة إليها، وسنتحدث عن أساسيات REST - وسنناقش كيفية تنفيذها؛ دعونا نتطرق إلى ممارسات الويب الأساسية التي تعتمد ولا تعتمد على هذه التقنية. سنتعلم أيضًا كيفية كتابة وثائق جيدة بأقل جهد، ونرى ما هي طرق الإصدار الموجودة لواجهات برمجة تطبيقات RESTful.

الجزء 1. النظرية

لذلك، كما نعلم جميعًا، API هي واجهة برمجة التطبيقات، وهي مجموعة من القواعد والآليات التي يتفاعل من خلالها تطبيق أو مكون واحد مع الآخرين

لماذا تعد واجهة برمجة التطبيقات الجيدة مهمة؟

  • سهولة الاستخدام والدعم. واجهة برمجة التطبيقات الجيدة سهلة الاستخدام والصيانة.
  • تحويل جيد بين المطورين. إذا أحب الجميع واجهة برمجة التطبيقات (API) الخاصة بك، فسوف يأتي إليك عملاء ومستخدمون جدد.
  • زيادة شعبية خدمتك. كلما زاد عدد مستخدمي واجهة برمجة التطبيقات (API)، زادت شعبية خدمتك.
  • عزل أفضل للمكونات. كلما كانت بنية API أفضل، كان عزل المكونات أفضل.
  • انطباع جيد عن المنتج. واجهة برمجة التطبيقات (API) تشبه واجهة مستخدم المطورين؛ هذا هو ما ينتبه إليه المطورون أولاً عند مقابلة المنتج. إذا كانت واجهة برمجة التطبيقات (API) منحنية، فإنك، كخبير تقني، لن توصي الشركات باستخدام مثل هذا المنتج عن طريق شراء شيء ما من طرف ثالث.

الآن دعونا نرى ما هي أنواع واجهات برمجة التطبيقات الموجودة.

أنواع واجهات برمجة التطبيقات حسب طريقة التنفيذ:

  • واجهات برمجة التطبيقات لخدمة الويب
    • XML-RPC وJSON-RPC
  • واجهات برمجة التطبيقات WebSockets
  • واجهات برمجة التطبيقات المستندة إلى المكتبة
    • جافا سكريبت
  • واجهات برمجة التطبيقات المستندة إلى الفئة
    • واجهة برمجة التطبيقات C#
  • وظائف نظام التشغيل والروتين
    • الوصول إلى نظام الملفات
    • الوصول إلى واجهة المستخدم
  • كائن APIs عن بعد
    • كوربا
    • .نت عن بعد
  • واجهات برمجة تطبيقات الأجهزة
    • تسريع الفيديو (OpenCL...)
    • محركات الأقراص الصلبة
    • حافلة PCI


كما نرى، تتضمن واجهات برمجة تطبيقات الويب XML-RPC وJSON-RPC وSOAP وREST.

يعد RPC (استدعاء الإجراء عن بعد) مفهومًا قديمًا جدًا، حيث يجمع بين البروتوكولات القديمة والمتوسطة والحديثة التي تسمح لك باستدعاء طريقة ما في تطبيق آخر. XML-RPC هو بروتوكول ظهر في عام 1998 بعد وقت قصير من ظهور XML. كان مدعومًا في البداية من قبل Microsoft، ولكن سرعان ما تحولت Microsoft بالكامل إلى SOAP، لذلك لن نجد فئات تدعم هذا البروتوكول في .Net Framework. على الرغم من ذلك، لا يزال XML-RPC يعيش حتى يومنا هذا بلغات مختلفة (خاصة PHP) - ويبدو أنه نال حب المطورين بسبب بساطته.

ظهر SOAP أيضًا في عام 1998 من خلال جهود Microsoft. تم الإعلان عنه كثورة في عالم البرمجيات. هذا لا يعني أن كل شيء سار وفقًا لخطة Microsoft: فقد كان هناك قدر كبير من الانتقادات بسبب تعقيد البروتوكول وثقله. وفي الوقت نفسه، كان هناك من اعتبر الصابون طفرة حقيقية. استمر البروتوكول في التطور وإنتاج العشرات من المواصفات الجديدة، حتى عام 2003 وافق W3C على SOAP 1.2 كتوصية، والذي لا يزال الأحدث. تبين أن عائلة SOAP مثيرة للإعجاب: WS-Addressing، WS-Enumeration، WS-Eventing، WS-Transfer، WS-Trust، WS-Federation، Web Single Sign-On.

ثم، بطبيعة الحال، ظهر نهج بسيط حقًا - الراحة. يشير الاختصار REST إلى نقل الحالة التمثيلية - "نقل حالة التمثيل" أو، بشكل أفضل، عرض البيانات بتنسيق مناسب للعميل. تمت صياغة مصطلح "REST" بواسطة Roy Fielding في عام 2000. الفكرة الأساسية لـ REST هي أن كل استدعاء للخدمة يأخذ تطبيق العميل إلى حالة جديدة. في جوهره، REST ليس بروتوكولًا أو معيارًا، ولكنه نهج وأسلوب معماري لتصميم واجهة برمجة التطبيقات (API).

ما هي مبادئ REST؟

  • بنية خادم العميل- بدون هذا، لا يمكن تصور الراحة.
  • أي بيانات هي مورد.
  • أي مورد لديه معرف، والتي يمكن الحصول على البيانات منها.
  • يمكن ربط الموارد ببعضها البعض- لهذا، يتم إرسال معرف أو، كما هو موصى به في كثير من الأحيان، رابطًا كجزء من الاستجابة. لكنني لم أصل إلى النقطة التي أصبح فيها كل شيء على ما يرام بحيث يمكنني بسهولة استخدام الروابط.
  • يتم استخدام أساليب HTTP القياسية(GET، POST، PUT، DELETE) - نظرًا لأنها مدرجة بالفعل في البروتوكول، فيمكننا استخدامها لبناء إطار عمل للتفاعل مع خادمنا.
  • الخادم لا يخزن الحالة- هذا يعني أن الخادم لا يفصل مكالمة عن أخرى، ولا يخزن جميع الجلسات في الذاكرة. إذا كان لديك نوع من السحابة القابلة للتطوير، أو نوع من مزرعة الخوادم التي تنفذ خدمتك، فليست هناك حاجة لضمان اتساق حالة هذه الخدمات بين جميع العقد التي لديك. وهذا يبسط القياس إلى حد كبير - عند إضافة عقدة أخرى، كل شيء يعمل بشكل جيد.

لماذا الراحة جيدة؟

  • انه بسيط جدا!
  • سوف نقوم بإعادة استخدام المعايير الحاليةوالتي تم استخدامها لفترة طويلة جدًا ويتم استخدامها على العديد من الأجهزة.
  • يعتمد REST على HTTP=> جميع الأشياء الجيدة متاحة:
    • التخزين المؤقت.
    • التحجيم.
    • الحد الأدنى من التكاليف العامة.
    • رموز الخطأ القياسية.
  • معدل انتشار جيد جدًا(حتى أجهزة إنترنت الأشياء تعرف بالفعل كيفية تشغيل HTTP).
أفضل الحلول (مستقلة عن التكنولوجيا)
ما هي أفضل الحلول في العالم الحديث التي لا تتعلق بتنفيذ محدد؟ أوصي بالتأكيد باستخدام هذه الحلول:
  • SSL في كل مكان- أهم شيء في خدمتك، لأنه بدون ترخيص SSL والمصادقة لا معنى لهما.
  • التوثيق والإصدارالخدمة - من أول يوم عمل.
  • يجب أن تعود أساليب POST وPUTقم بإرجاع الكائن الذي قاموا بتغييره أو إنشائه - سيؤدي ذلك إلى تقليل الوقت المستغرق للوصول إلى الخدمة بمقدار النصف.
  • يدعم التصفية والفرز والترحيل- من المرغوب فيه للغاية أن يكون هذا قياسيًا وأن يعمل خارج الصندوق.
  • دعم نوع الوسائط. MediaType هي طريقة لإخبار الخادم بالتنسيق الذي تريد أن يكون المحتوى به. إذا أخذت أي تطبيق قياسي لواجهة برمجة تطبيقات الويب وقمت بالوصول إليه من المتصفح، فستمنحك واجهة برمجة التطبيقات XML، وإذا قمت بالوصول إليه من خلال ساعي البريد، فسوف يُرجع JSON.
  • بريتيبرينت و gzip. لا تقلل من الطلبات ولا تجعلها مضغوطة لـ JSON (الاستجابة التي تأتي من الخادم). يكون الحمل على Prettyprint بوحدات النسبة المئوية، والتي يمكن رؤيتها إذا نظرت إلى مقدار علامات التبويب التي تستهلكها بالنسبة إلى الحجم الإجمالي للرسالة. إذا قمت بإزالة علامات التبويب وأرسلت كل شيء في سطر واحد، فسوف تتعب من تصحيح الأخطاء. أما gzip فهو يعطي فوائد عدة مرات. على وجه الخصوص، أوصي بشدة باستخدام كل من Prettyprint وgzip.
  • استخدم فقط آلية التخزين المؤقت القياسية (ETag) وآخر تعديل (تاريخ آخر تعديل)- هاتان المعلمتان كافيتان للخادم للسماح للعميل بفهم أن المحتوى لا يتطلب التحديث. ليس هناك فائدة من اختراع شيء خاص بك هنا.
  • استخدم دائمًا رموز خطأ HTTP القياسية. خلاف ذلك، سيتعين عليك في يوم من الأيام أن تشرح لشخص ما سبب قرارك بأن العميل يحتاج إلى تفسير الخطأ 419 في مشروعك تمامًا كما توصلت إليه لسبب ما. هذا غير مريح وقبيح - العميل لن يشكرك على هذا!
خصائص طرق HTTP

سنتحدث اليوم فقط عن GET، POST، PUT، DELETE.

بالحديث بإيجاز عن العناصر الأخرى المعروضة في الجدول، الخيارات - الحصول على إعدادات الأمان، الرأس - الحصول على الرؤوس بدون نص الرسالة، التصحيح - تغيير المحتوى جزئيًا.

كما ترون، جميع الطرق باستثناء POST الواردة في الجدول غير فعالة. العجز هو القدرة على إجراء نفس الاتصال بالخدمة عدة مرات، وستكون الاستجابة هي نفسها في كل مرة. بمعنى آخر، لا يهم سبب أو عدد المرات التي قمت فيها بهذا الإجراء. لنفترض أنك كنت تقوم بإجراء تغيير على إجراء كائن (PUT) وتلقيت خطأ. أنت لا تعرف سبب ذلك وفي أي لحظة، لا تعرف ما إذا كان الكائن قد تغير أم لا. ولكن، بفضل العجز، نضمن لك تنفيذ هذا الإجراء مرة أخرى، بحيث يمكن للعملاء الاطمئنان إلى سلامة بياناتهم.

"آمن" يعني أن الوصول إلى الخادم لا يغير المحتوى. لذلك، يمكن استدعاء GET عدة مرات، لكنه لن يغير أي محتوى. إذا كان الأمر يتعلق بتغيير المحتوى، نظرًا لإمكانية تخزين GET مؤقتًا، فسيتعين عليك محاربة التخزين المؤقت واختراع بعض المعلمات الصعبة.

الجزء 2. الممارسة
اختيار التكنولوجيا

الآن بعد أن فهمنا كيفية عمل REST، يمكننا البدء في كتابة RESTful API - وهي خدمة تتبع مبادئ REST. لنبدأ باختيار التكنولوجيا.

الخيار الأول - خدمات صندوق العمل العالمي. كل من عمل مع هذه التكنولوجيا عادة لا يرغب في العودة إليها - فهي لها عيوب خطيرة ومزايا قليلة:
– webHttpBinding فقط (لماذا إذن الباقي؟..).
- يتم دعم HTTP Get & POST فقط (هذا كل شيء).
+ صيغ مختلفة XML، JSON، ATOM.

الخيار الثاني - واجهة برمجة تطبيقات الويب. في هذه الحالة، المزايا واضحة:
+ بسيط جدا.
+ مفتوح المصدر.
+ جميع ميزات HTTP.
+ جميع ميزات MVC.
+ خفيفة الوزن.
+ يدعم أيضًا مجموعة من التنسيقات.

بطبيعة الحال، نختار Web API. الآن دعنا نختار الاستضافة المناسبة لـ Web API.

اختيار استضافة Web API

هناك عدد غير قليل من الخيارات هنا:

  • ASP.NET MVC (القديم الجيد).
  • أزور (البنية السحابية).
  • OWIN - واجهة ويب مفتوحة لـ .NET (تطوير جديد من Microsoft).
  • استضافة ذاتية
OWI
فوزليست منصة أو مكتبة، ولكنها مواصفات تزيل الاقتران القوي لتطبيق الويب من تنفيذ الخادم. يسمح بتشغيل التطبيقات على أي نظام أساسي يدعم OWIN دون تعديل. في الواقع، المواصفات بسيطة جدًا - إنها مجرد "قاموس" للمعلمات وقيمها. يتم تعريف المعلمات الأساسية في المواصفات.

يتلخص OWIN في بنية بسيطة للغاية:

وفقًا للمخطط، نرى أن هناك مضيفًا به خادم يدعم "قاموسًا" بسيطًا للغاية يتكون من قائمة "قيمة المعلمة". يتم تكوين كافة الوحدات التي تتصل بهذا الخادم بهذه الطريقة. الخادم الذي يدعم هذا العقد، المرتبط بمنصة معينة، قادر على التعرف على جميع هذه المعلمات وتهيئة البنية التحتية وفقًا لذلك. اتضح أنه إذا كتبت خدمة تعمل مع OWIN، فيمكنك نقلها بحرية بين الأنظمة الأساسية دون تغيير الكود واستخدام نفس الشيء على أنظمة تشغيل أخرى.

كاتانا- تنفيذ OWIN من مايكروسوفت. يسمح لك باستضافة تجميعات OWIN في IIS. هذا هو ما يبدو، بسيط جدا:

Namespace RestApiDemo (بدء تشغيل الفئة العامة ( public void Configuration(IAppBuilder app) ( var config = new HttpConfiguration(); config.MapHttpAttributeRoutes(); app.UseWebApi(config); ) ) )

أنت تشير إلى الفئة التي تنتمي إليها شركتك الناشئة. هذا ملف dll بسيط يتم التقاطه بواسطة IIS. يتم استدعاء التكوين. هذا الكود كافي لتشغيل كل شيء.

تصميم الواجهة
الآن دعونا نصمم الواجهة ونرى كيف يجب أن يبدو كل شيء وما هي القواعد التي يجب أن يتبعها. جميع الموارد في REST هي أسماء، وهي أشياء يمكن لمسها ولمسها.

كمثال، لنأخذ نموذجًا بسيطًا يتضمن جداول القطارات في المحطات. فيما يلي أمثلة لطلبات REST البسيطة:

  • كيانات واجهة برمجة التطبيقات الجذرية (المستقلة):
    • الحصول على / المحطات - الحصول على جميع المحطات.
    • الحصول على /stations/123 - احصل على معلومات حول المحطة ذات المعرف = 123.
    • الحصول على / القطارات - الجدول الزمني لجميع القطارات.
  • الكيانات التابعة (من الجذر):
    • الحصول على /stations/555/departures - القطارات التي تغادر المحطة 555.
مراقب

إذن، لدينا محطات، والآن نحتاج إلى كتابة وحدة تحكم بسيطة:

وحدة تحكم محطات السكك الحديدية من الفئة العامة: ApiController ( public IEnumerable GetAll () (إرجاع بيانات الاختبار؛) RailwayStationModel testData = /*التهيئة هنا*/)

هذا هو التوجيه القائم على السمة. نشير هنا إلى اسم وحدة التحكم ونطلب قائمة (في هذه الحالة، بيانات اختبار عشوائية).

أوداتا (www.odata.org)

تخيل الآن أن لديك بيانات أكثر مما تحتاجه عن العميل (من غير المنطقي أن تحمل أكثر من مائة). وفي الوقت نفسه، بالطبع، لا تريد أن تكتب أي ترقيم صفحات بنفسك. بدلا من ذلك، هناك طريقة سهلة - لاستخدام الإصدار الخفيف من OData، الذي يدعمه Web API.

وحدة تحكم محطات السكك الحديدية من الدرجة العامة: ApiController (IQueryable العامة GetAll() ( إرجاع testData.AsQueryable(); ) RailwayStationModel testData = /*التهيئة هنا*/ )

يتيح لك IQueryable استخدام العديد من آليات التصفية ومعالجة البيانات البسيطة والفعالة من جانب العميل. الشيء الوحيد الذي عليك القيام به هو توصيل مجموعة OData من NuGet، وتحديد EnableQuery وإرجاع واجهة iQueryable.

يتمثل الاختلاف الرئيسي بين هذا الإصدار الخفيف والإصدار الكامل في عدم وجود وحدة تحكم تقوم بإرجاع البيانات التعريفية. تغير OData الكاملة الإجابة قليلاً (فهي تغلف النموذج الذي سترجعه في غلاف خاص) ويمكنها إرجاع شجرة ذات صلة من الكائنات التي تريد منحها لها. أيضًا، لا يمكن للإصدار الخفيف من OData القيام بأشياء مثل الانضمام والعد وما إلى ذلك.

معلمات الاستعلام

إليك ما يمكنك فعله:

  • $filter - عامل التصفية بالاسم، على سبيل المثال. يمكن الاطلاع على جميع الوظائف على موقع OData الإلكتروني - فهي مفيدة جدًا وتسمح لك بتحديد العينة بشكل كبير.
  • $select هو شيء مهم جدًا. إذا كان لديك مجموعة كبيرة وجميع الكائنات سميكة، ولكن في نفس الوقت تحتاج إلى إنشاء نوع من القائمة المنسدلة، حيث لا يوجد شيء سوى المعرف والاسم الذي تريد عرضه، فستساعدك هذه الوظيفة، والتي سوف تبسيط وتسريع التفاعل مع الخادم.
  • $orderby - الفرز.
  • $top و $skip - الحد الأقصى للعينات.

وهذا يكفي لتجنب إعادة اختراع العجلة بنفسك. يمكن لمكتبة JS القياسية مثل Breeze القيام بكل هذا.

سمة تمكين الاستعلام
في الواقع، OData هو نوع الأشياء التي يمكنها بسهولة إطلاق النار على قدمها. إذا كان لديك ملايين السجلات في الجدول الخاص بك، وتحتاج إلى سحبها من الخادم إلى العميل، فسيكون ذلك صعبا، وإذا كان هناك العديد من هذه الطلبات، فسيكون ذلك قاتلا تماما.

في مثل هذه الحالات، تحتوي سمة EnableQuery (انظر الكود أعلاه) على مجموعة من المعلمات التي يمكنك من خلالها تقييد الكثير: لا تعطي صفوفًا أكثر من اللازم، ولا تسمح بالانضمام، والعمليات الحسابية، وما إلى ذلك. أكتبها بنفسك لا تحتاج إلى أي شيء.

  • مشغلي الحساب المسموح بهم
  • الوظائف المسموح بها
  • المشغلين المنطقيين المسموح بهم
  • مسموح بهOrderByProperties
  • خيارات الاستعلام المسموح بها
  • EnableConstantParameterization
  • ضمان الطلب المستقر
  • HandleNullPropagation
  • MaxAnyAllExpressionDepth
  • ماكس إكسبانسيونديبث
  • MaxNodeCount
  • MaxOrderByNodeCount
  • MaxSkip
  • com.maxTop
  • مقاس الصفحه

وحدة تحكم تابعة
لذا، إليك أمثلة على أبسط طلبات REST:

  • الحصول على / المحطات - الحصول على جميع المحطات
  • الحصول على / القطارات - الجدول الزمني لجميع القطارات
  • احصل على /stations/555/arrivals
  • احصل على /stations/555/departures

لنفترض أن لدينا محطة 555، ونريد الحصول على جميع رحلات المغادرة والقادمة. من الواضح أنه يجب استخدام كيان هنا يعتمد على كيان المحطة. ولكن كيف نفعل ذلك في وحدات التحكم؟ إذا قمنا بكل هذا باستخدام سمات التوجيه ووضعناها في فئة واحدة، فمن الواضح أنه في مثال مثل مثالنا لا توجد مشاكل. ولكن إذا كان لديك عشرات الكيانات المتداخلة وازداد العمق بشكل أكبر، فسوف يتحول كل ذلك إلى تنسيق غير مدعوم.

وهناك حل بسيط - يمكنك عمل متغيرات في سمات التوجيه في وحدات التحكم:

فئة عامة TrainsFromController: TrainsController (عام IQueryable GetAll(int station) (إرجاع GetAllTrips().Where(x =>

وبناء على ذلك، ضع كافة الكيانات التابعة في وحدة تحكم منفصلة. كم عددهم غير مهم على الإطلاق، لأنهم يعيشون بشكل منفصل. من وجهة نظر Web API، سيتم إدراكها من خلال وحدات تحكم مختلفة - لا يبدو أن النظام نفسه يعرف أنها تابعة، على الرغم من ظهورها على هذا النحو في عنوان URL.

المشكلة الوحيدة التي تطرح هي أن لدينا هنا "محطات"، وقبل ذلك كانت هناك "محطات". إذا قمت بتغيير شيء ما في مكان واحد ولم تغير أي شيء في مكان آخر، فلن ينجح شيء. ومع ذلك، هناك حل بسيط - استخدم ثوابت التوجيه:

فئة ثابتة عامة TrainsFromControllerRoutes (سلسلة const العامة BasePrefix = RailwayStationsControllerRoutes.BasePrefix + "/(station:int)/departures"; سلسلة const العامة GetById = "(id:int)"; )

ثم ستبدو وحدة التحكم التابعة كما يلي:

فئة عامة TrainsFromController: TrainsController (عام IQueryable GetAll(int station) ( return GetAll().Where(x => x.OriginRailwayStationId == station); ) )

يمكنك إجراء عمليات بسيطة لوحدات التحكم التابعة - ما عليك سوى تحديد المسار وحسابه بنفسك، ومن ثم لن ترتكب أي خطأ. بالإضافة إلى ذلك، هذه الأشياء مفيدة للاختبار. إذا كنت تريد كتابة اختبار ثم تريد إدارته، وليس تشغيل كل ملايين الاختبارات في كل مرة وتصحيح جميع الأسطر التي تم تحديد عناوين URL النسبية فيها، فيمكنك أيضًا استخدام هذه الثوابت. عندما تقوم بتغييرها، تتغير بياناتك في كل مكان. أنها مريحة للغاية.

الخام
لذلك، ناقشنا كيف قد تبدو أبسط عمليات GET. الجميع يفهم كيفية القيام بـ GET واحد. ولكن إلى جانب ذلك، نحن بحاجة لمناقشة ثلاث عمليات أخرى.
  • POST - إنشاء كيان جديد
    • POST /Stations – وصف JSON للكيان بأكمله. يضيف الإجراء كيانًا جديدًا إلى المجموعة.
    • إرجاع الكيان الذي تم إنشاؤه (أولاً، حتى لا تكون هناك رحلات مزدوجة إلى الخادم، وثانيًا، بحيث، إذا لزم الأمر، قم بإرجاع المعلمات التي تم حسابها في هذا الكائن والتي يحتاجها العميل من الخادم).
  • PUT - تغيير الكيان
    • PUT /Stations/12 - قم بتغيير الكيان بالمعرف = 12. ستتم كتابة JSON الذي يأتي في المعلمة.
    • إرجاع الكيان المعدل. المسار الذي تم تطبيقه عدة مرات يجب أن يقود النظام إلى نفس الحالة.
  • يمسح
    • DELETE /Stations/12 - احذف كيانًا بالمعرف = 12.

المزيد من الأمثلة الخام:

  • POST / المحطات - إضافة محطة.
  • POST /Stations/1/Departures - أضف معلومات حول المغادرة من المحطة 1.
  • حذف /Stations/1/Departures/14 - حذف سجل المغادرة من المحطة 1.
  • الحصول على /Stations/33/Departures/10/Tickets - قائمة التذاكر المباعة للمغادرة 10 من المحطة 33.

من المهم أن نفهم أن العقد هي بالضرورة نوع من الكيان، شيء يمكن "لمسه" (تذكرة، قطار، حقيقة مغادرة القطار، وما إلى ذلك).

أنماط مضادة
فيما يلي أمثلة لما لا يجب فعله:
  • احصل على /Stations/?op=departure&train=11
    هنا يتم استخدام سلسلة الاستعلام ليس فقط لنقل البيانات، ولكن أيضًا للإجراءات.
  • الحصول على / المحطات / حذف الكل
    هذا مثال واقعي للحياة. نحن هنا نقوم بإجراء GET على هذا العنوان، ومن المفترض نظريًا إزالة جميع الكيانات من المجموعة - ونتيجة لذلك، يتصرف بشكل غير متوقع بسبب التخزين المؤقت.
  • ما بعد /GetUserActivity
    هذا هو في الواقع GET، والذي يتم كتابته كـ POST. كانت هناك حاجة إلى POST بسبب معلمات الطلب الموجودة في النص، ولكن لا يمكن لـ GET تمرير أي شيء إلى النص - لا يمكن تمرير GET إلا إلى سلسلة الاستعلام. GET لا يدعم حتى الجسم وفقًا للمعايير.
  • نشر /محطات/إنشاء
    هنا يتم تحديد الإجراء كجزء من عنوان URL - وهذا زائد عن الحاجة.
تصميم واجهة برمجة التطبيقات (API).
لنفترض أن لديك واجهة برمجة التطبيقات (API) التي تريد تقديمها للأشخاص، ولديك نموذج مجال. كيف ترتبط كيانات API بنموذج المجال؟ نعم، إنهما غير مرتبطين بأي شكل من الأشكال في الواقع. ليست هناك حاجة لذلك: ما تفعله في واجهة برمجة التطبيقات (API) ليس له علاقة بنموذج المجال الداخلي الخاص بك.

قد يطرح السؤال، كيفية تصميم واجهة برمجة التطبيقات (API) إذا لم تكن CRUD؟ للقيام بذلك، نقوم بتسجيل أي إجراءات كأوامر تغيير. نحن نقوم بحفظ الأمر وقراءته وحذفه وإجراء GET والتحقق من حالة هذا الأمر. الحصول على من مجموعة الأوامر - تحصل على قائمة بجميع الأوامر التي أرسلتها إلى أي كيان محدد.

نموذج المجال
سنتحدث عن العلاقة بين نموذج المجال والكائنات. في المثال، لدينا فندق (فندق)، وهناك حجوزات (حجز) وغرف (غرفة) وأجهزة (جهاز) مرتبطة بها. وفي مشروعنا، أصبح من الممكن التحكم في الغرف من خلال هذه الأجهزة.

لكن هنا تكمن المشكلة: الجهاز كيان يعيش حياته الخاصة، وليس من الواضح كيفية فصله عن الفندق. لكن فصل الفندق والأجهزة هو في الواقع أمر بسيط للغاية - سيساعدك DDD. بادئ ذي بدء، تحتاج إلى معرفة أين تقع حدود مناطق المجال وأين تقع حدود الكيانات المسؤولة عن اتساق النظام.

السياق المحدود (قبل الميلاد)
السياق المحدود (المجال الفرعي المعزول) - في الواقع، مجموعات من الكائنات المستقلة عن بعضها البعض ولها نماذج مستقلة تمامًا (مختلفة). في المثال، يمكننا أن نأخذ الفنادق والأجهزة ونفصلها إلى مركزي أعمال مختلفين - فهي ليست مترابطة، ولكن هناك ازدواجية. يظهر كيان إضافي (الجهاز المرفق):

لدينا هنا تمثيلات مختلفة لنفس الجهاز، ولا حرج في ذلك.

في DDD، المسار التجميعي هو كيان يمتلك كافة العناصر التابعة. هذه قمة شجرتنا (الفندق)؛ شيء يمكن من خلاله سحب كل شيء آخر. لكن لا يمكنك التعامل مع AttachedDevice بهذه الطريقة - فهو غير موجود، وليس له أي معنى. وبالمثل، فإن فصول الغرفة والحجز ليس لها أي معنى، كونك مطلقًا من الفندق. ولذلك، فإن الوصول إلى جميع هذه الفئات يكون حصريًا من خلال الكيان الجذر، من خلال الفندق، في هذه الحالة. الجهاز عبارة عن مسار مختلف منذ البداية، وشجرة مختلفة بمجموعة مختلفة من الحقول.

لذا، إذا فهمت أن لديك كيانًا واحدًا يلعب في مجالين مختلفين، فما عليك سوى قطعه - وسيكون مجرد إسقاط للكيان الرئيسي. في AttachedDevice، على سبيل المثال، ستكون هناك حقول تحتوي على رقم الغرفة، ولكن في الجهاز لن تكون هناك حاجة إلى مثل هذه الحقول.

و هنا أمثلة الاستعلام، كيف يمكن أن يبدووا في نموذج المجال هذا:

  • PUT /hotels/555/rooms/105/attachedDevices - استبدل المجموعة الكاملة للأجهزة المتصلة بجهاز جديد.
  • POST /hotels/555/rooms/105/attachedDevices - قم بتوصيل جهاز آخر.
  • حذف /hotels/12 - احذف وصف الفندق بالمعرف=12.
  • POST /hotels/123/reservations - قم بإنشاء حجز جديد في معرف الفندق = 123.
CQRS - فصل مسؤولية استعلام الأوامر

لن أتحدث عن هذه البنية الآن، لكني أريد أن أوضح بإيجاز مبدأ عملها. تعتمد بنية CQRS على فصل دفق البيانات.

لدينا موضوع واحد يرسل من خلاله المستخدم أمرًا إلى الخادم لتغيير المجال. ومع ذلك، ليس حقيقة أن التغيير سيحدث بالفعل - فالمستخدم لا يتعامل مع البيانات مباشرة. لذلك، بعد أن يرسل المستخدم أمرًا لتغيير كيان ما، يقوم الخادم بمعالجته ووضعه في نوع من النماذج المُحسّنة للقراءة - تقرأه واجهة المستخدم.

سيسمح لك هذا النهج باتباع مبادئ REST بسهولة بالغة. إذا كان هناك أمر، فهناك كيان "قائمة الأوامر".

الراحة دون وضع
في عالم CRUD البسيط، PUT هو الشيء الذي يغير الكائنات. ولكن إذا اتبعنا مبدأ CQRS بدقة وقمنا بكل شيء من خلال الأوامر، فسيختفي PUT لأننا لا نستطيع تغيير الكائنات. بدلاً من ذلك، يمكننا فقط إرسال أمر إلى الكائن لتغييره. في الوقت نفسه، يمكنك تتبع حالة التنفيذ، وإلغاء الأوامر (DELETE)، وتخزين سجل التغييرات بسهولة، ولا يغير المستخدم أي شيء، ولكنه ببساطة يبلغ عن النوايا.

لا يزال نموذج REST بدون PUT مثيرًا للجدل ولم يتم اختباره بالكامل، ولكنه قابل للتطبيق بشكل جيد في بعض الحالات.

الحبيبات الدقيقة VS الحبيبات الخشنة
تخيل أنك تقدم خدمة كبيرة، وجسمًا كبيرًا. هنا لديك طريقتان: واجهة برمجة التطبيقات (API) ذات الحبيبات الدقيقة وواجهة برمجة التطبيقات (API) ذات الحبيبات الخشنة (واجهة برمجة التطبيقات (API) "ذات الحبيبات الدقيقة" و"الحبيبات الخشنة").

واجهة برمجة التطبيقات الدقيقة الحبيبات:

  • الكثير من الأشياء الصغيرة.
  • منطق الأعمال يذهب إلى جانب العميل.
  • عليك أن تعرف كيف ترتبط الأشياء.

واجهة برمجة التطبيقات ذات الحبيبات الخشنة:

  • إنشاء المزيد من الكيانات.
  • من الصعب إجراء تغييرات محلية، على سبيل المثال.
    • نشر / المدونات / (المعرف) / الإعجابات.
  • تحتاج إلى مراقبة الحالة على العميل.
  • لا يمكن حفظ الكائنات الكبيرة جزئيًا.

في البداية، أنصحك بتصميم واجهة برمجة تطبيقات دقيقة: في كل مرة تقوم فيها بإنشاء كائن، أرسله إلى الخادم. لكل إجراء من جانب العميل، يتم إجراء اتصال بالخادم. ومع ذلك، فإن العمل مع الكيانات الصغيرة أسهل من العمل مع الكيانات الكبيرة: إذا كتبت كيانًا كبيرًا، فسيكون من الصعب عليك قطعه لاحقًا، وسيكون من الصعب إجراء تغييرات صغيرة وسحب أجزاء مستقلة منه. ولذلك فمن الأفضل أن نبدأ بالكيانات الصغيرة ثم نوسعها تدريجياً.

ترقيم الإصدار
لقد حدث أن صناعتنا لديها موقف مريح للغاية تجاه العقود. لسبب ما، يعتقد الناس أنهم إذا قاموا بإنشاء واجهة برمجة التطبيقات، فهي واجهة برمجة التطبيقات الخاصة بهم والتي يمكنهم من خلالها فعل ما يريدون. ولكن هذا ليس صحيحا. إذا سبق لك أن كتبت واجهة برمجة التطبيقات (API) وأعطتها لطرف مقابل واحد على الأقل، فكل شيء هو الإصدار 1.0. يجب أن تؤدي أي تغييرات الآن إلى تغيير الإصدار. بعد كل شيء، سيقوم الأشخاص بربط الكود الخاص بهم بالإصدار الذي قدمته لهم.

في المشروع الأخير، اضطررنا إلى التراجع عن واجهة برمجة التطبيقات (API) عدة مرات ببساطة لأنه تم إعطاؤها للعميل - لقد قمنا بتغيير رموز الخطأ، لكن العميل قد اعتاد بالفعل على الرموز القديمة.

ما هي الخيارات المعروفة حاليًا لترقيم إصدارات Web API؟

أبسط شيء هو تحديد الإصدار في عنوان URL.

فيما يلي الخيارات الجاهزة عندما لا تحتاج إلى القيام بأي شيء بنفسك:

إليك خيارًا جاهزًا مثيرًا للاهتمام.

هذا مجرد توجيه سمة مع القيد - إذا كنت قد فعلت أي كائنات خطيرة، فمن المحتمل أنك قد فعلت القيد. بناءً على رقم الإصدار في هذه السمة، قام الرجال ببساطة بتنفيذ القيد. وبناءً على ذلك، يمكنك تعيين نفس السمة بإصدارات مختلفة، ولكن نفس اسم وحدة التحكم، لفئتين مختلفتين وتحديد إصدارات مختلفة. كل شيء يعمل خارج الصندوق..

VersionedRoute("v2/values"، الإصدار = 2)]
التكوين.تكوين الإصدار (
versioningHeaderName: "version"، vesioningMediaTypes: null);
التكوين.تكوين الإصدار (
versioningHeaderName: فارغة،
vesioningMediaTypes: new("application/vnd.model"));

توثيق
هناك شيء رائع مفتوح المصدر وله العديد من الاستخدامات المختلفة - Swagger. نستخدمه مع محول خاص - Swashbuckle.
  • http://swagger.io/
  • https://github.com/domaindrivendev/Swashbuckle
متعجرف: httpConfiguration .EnableSwagger(c => c.SingleApiVersion("v1", "Demo API")) .EnableSwaggerUi(); الفراغ الثابت العام RegisterSwagger(تكوين HttpConfiguration هذا) ( config.EnableSwagger(c => ( c.SingleApiVersion("v1" "، "DotNextRZD.PublicAPI") .Description("DotNextRZD Public API") .TermsOfService("الشروط والأحكام") .Contact(cc => cc .Name("Vyacheslav Mikhaylov") .Url("http://www" .dotnextrzd.com") .البريد الإلكتروني(" [البريد الإلكتروني محمي]")).License(lc => lc.Name("License").Url("http://tempuri.org/license")); c.IncludeXmlComme nts(GetXmlCommentFile()); c.GroupActionsBy(GetControllerGroupingKey) ; c.OrderActionGroupsBy(new CustomActionNameComparer()); c.CustomProvider(p => new CustomSwaggerProvider(config, p)); EnableSwaggerUi(c => ( c.InjectStylesheet(Assembly.GetExecutingAssembly(), "DotNextRZD.PublicApi .Swagger. Styles.SwaggerCustom.css"); ))); ) )

العلامات: إضافة العلامات

يوجد في الجزء الناطق باللغة الروسية من الإنترنت عدد كبير من المقالات المخصصة لخدمات الويب المستندة إلى SOAP وXML-RPC، ولكن لسبب ما لا يوجد شيء تقريبًا حول بنية REST الجديرة بالملاحظة (ولكنها أقل شيوعًا).

توضح هذه المقالة أساسيات هذه البنية وإمكانياتها وأمثلة على استخدامها.

ما هو الراحة

REST (نقل الحالة التمثيلية) هو نمط من هندسة البرمجيات للأنظمة الموزعة مثل شبكة الويب العالمية، والتي تُستخدم عادةً لبناء خدمات الويب. تمت صياغة مصطلح REST في عام 2000 بواسطة Roy Fielding، أحد مؤلفي بروتوكول HTTP. تسمى الأنظمة التي تدعم REST أنظمة RESTful.

بشكل عام، REST عبارة عن واجهة بسيطة جدًا لإدارة المعلومات دون استخدام أي طبقات داخلية إضافية. يتم تعريف كل جزء من المعلومات بشكل فريد بواسطة معرف عالمي، مثل عنوان URL. ولكل عنوان URL بدوره تنسيق محدد بدقة.

والآن أصبح الأمر نفسه أكثر وضوحًا:

ويعني عدم وجود طبقات داخلية إضافية أن البيانات يتم نقلها بنفس شكل البيانات نفسها. أولئك. نحن لا نغلف البيانات في XML مثل SOAP وXML-RPC، ولا نستخدم AMF كما يفعل Flash، وما إلى ذلك. نحن فقط نعطي البيانات نفسها.

يتم تعريف كل جزء من المعلومات بشكل فريد بواسطة عنوان URL، مما يعني أن عنوان URL هو في الأساس المفتاح الأساسي لجزء البيانات. أولئك. على سبيل المثال، الكتاب الثالث من رف الكتب سيبدو مثل /book/3، والصفحة 35 في هذا الكتاب ستبدو مثل /book/3/page/35. من هنا نحصل على تنسيق محدد بدقة. علاوة على ذلك، لا يهم على الإطلاق التنسيق الذي توجد به البيانات في /book/3/page/35 - يمكن أن يكون HTML، أو نسخة ممسوحة ضوئيًا في شكل ملف jpeg، أو مستند Microsoft Word.

تعتمد كيفية إدارة معلومات الخدمة بالكامل على بروتوكول نقل البيانات. البروتوكول الأكثر شيوعًا هو بالطبع HTTP. لذلك، بالنسبة لـ HTTP، يتم تحديد الإجراء على البيانات باستخدام الطرق: GET (تلقي)، PUT (إضافة، استبدال)، POST (إضافة، تغيير، حذف)، DELETE (حذف). وبالتالي، يمكن تنفيذ إجراءات CRUD (إنشاء-قراءة-تحديث-حذف) باستخدام جميع الطرق الأربعة، أو فقط باستخدام GET وPOST.

إليك ما سيبدو عليه في المثال:

الحصول على /book/ - الحصول على قائمة بجميع الكتب
الحصول على /book/3/ - الحصول على الكتاب رقم 3
PUT /book/ - إضافة كتاب (البيانات في نص الطلب)

حذف /كتاب/3 - حذف كتاب

إضافة هامة:هناك ما يسمى بأنماط REST، والتي تختلف في ربط أساليب HTTP بما تفعله. على وجه الخصوص، تتعامل الأنماط المختلفة مع POST وPUT بشكل مختلف. ومع ذلك، فإن PUT مخصص للإنشاء أو إعادة التشغيل أو التحديث، ولم يتم تعريف هذا لـ POST (عملية POST عامة جدًا ولا يمكن ربط أي معنى محدد بها). لذلك، سيكون مثالي صحيحًا في هذا النموذج وفي النموذج إذا تم تبديل POST وPUT.

بشكل عام، يمكن استخدام POST لجميع إجراءات التغيير في وقت واحد:
POST /book/ – إضافة كتاب (البيانات في نص الطلب)
POST /book/3 - تغيير الكتاب (البيانات في نص الطلب)
POST /book/3 – حذف كتاب (نص الطلب فارغ)

يتيح لك هذا أحيانًا تجاوز المشكلات غير السارة المرتبطة برفض PUT وDELETE.

استخدام REST لبناء خدمات الويب.

كما تعلم، خدمة الويب هي تطبيق يعمل على شبكة الويب العالمية ويتم توفير الوصول إليه عبر بروتوكول HTTP، ويتم تبادل المعلومات باستخدام تنسيق XML. ولذلك، فإن تنسيق البيانات المرسلة في نص الطلب سيكون دائمًا XML.

لكل وحدة معلومات (info)، يتم تحديد 5 إجراءات. يسمى:

يحصل على معلومات/ (فِهرِس)- يحصل على قائمة بجميع الكائنات. كقاعدة عامة، هذه قائمة مبسطة، أي. يحتوي فقط على معرف الكائن وحقول الاسم، دون بيانات أخرى.

الحصول على / معلومات / (معرف) (منظر)- يتلقى معلومات كاملة عن الكائن.

ضع /معلومات/أو مشاركة /معلومات/ (يخلق)- إنشاء كائن جديد. يتم نقل البيانات في نص الطلب دون استخدام التشفير، حتى رمز urlencode. في PHP، يمكن الحصول على نص الطلب بهذه الطريقة:

الدالة getBody() (
إذا (! isset($HTTP_RAW_POST_DATA))
$HTTP_RAW_POST_DATA = file_get_contents("php://input");
إرجاع $HTTP_RAW_POST_DATA؛
}

نشر / معلومات / (معرف)أو وضع / معلومات / (معرف) (يحرر)- تغيير البيانات ذات المعرف (المعرف)، وربما استبدالها. يتم أيضًا نقل البيانات في نص الطلب، ولكن على عكس PUT، هناك بعض الفروق الدقيقة هنا. الحقيقة هي أن طلب POST يعني وجود بيانات لاحقة مشفرة url. أولئك. إذا لم تستخدم الترميز، فهذا يعد انتهاكًا للمعيار. هنا من يريد ذلك - البعض لا ينتبه للمعيار، والبعض الآخر يستخدم نوعًا من المتغير اللاحق.

حذف /المعلومات/(المعرف) (يمسح)- حذف البيانات ذات المعرف (المعرف).

اسمحوا لي أن أشير مرة أخرى إلى أنه في مثالنا /info/ - قد يعتمد على بعض المعلومات الأخرى، والتي يمكن (ويجب) أن تنعكس في عنوان URL:

/data/4/otherdata/6/info/3/ … وما شابه.

ما هي الاستنتاجات التي يمكن استخلاصها من هذا:

كما ترون، فإن بنية REST سهلة الاستخدام للغاية. حسب نوع الطلب الذي يصل، يمكنك تحديد ما يفعله على الفور دون فهم التنسيقات (على عكس SOAP، XML-RPC). يتم نقل البيانات دون استخدام طبقات إضافية، لذلك يعتبر REST أقل استهلاكًا للموارد، حيث لا تحتاج إلى تحليل الطلب لفهم ما يجب أن يفعله ولا تحتاج إلى ترجمة البيانات من تنسيق إلى آخر.

الاستخدام العملي.

الميزة الأكثر أهمية للخدمات هي أن أي نظام يمكنه العمل معها، سواء كان موقع ويب أو فلاش أو برنامج وما إلى ذلك، نظرًا لأن طرق تحليل XML وتنفيذ طلبات HTTP موجودة في كل مكان تقريبًا.

تعمل بنية REST على تبسيط هذه المهمة إلى حد كبير. بالطبع، في الواقع، ما تم وصفه لا يكفي، لأنه لا يمكنك منح أي شخص الفرصة لتغيير المعلومات، أي أن الترخيص والمصادقة مطلوبان أيضًا. ولكن يمكن حل هذه المشكلة بكل بساطة باستخدام أنواع مختلفة من الجلسات أو ببساطة مصادقة HTTP.

مرحبا عزيزي القراء! قبل أن تبدأ بقراءة هذا المقال، أود أن أصف الغرض من إنشائه وأخبرك ما الذي دفعني لكتابته.

في أحد مشاريع شركتنا، أصبح من الضروري تصميم تطبيق خادم بأسلوب REST. في البداية، بدا لنا أن هذه كانت مهمة بسيطة إلى حد ما وأن تجربتنا الخاصة فقط ستكون كافية لحلها.

ولكن عندما بدأت عملية تطوير البنية وتقديم خدمات REST إلى نمط واحد، بدأت أنا وزملائي في طرح قضايا مثيرة للجدل ووجهات نظر مختلفة حول تنفيذ هذا الجانب أو ذاك. ثم أدركنا أننا بحاجة إلى فتح Google والاستعانة بالحكمة الجماعية ودراسة أفضل الممارسات المقترحة التي ينبغي استخدامها عند تصميم تطبيق RESTful.

ستكون هذه المقالة مفيدة لأولئك الأشخاص الذين لديهم بالفعل بعض الخبرة في تطبيقات الويب (وربما مع خدمات REST)، ولكنهم بحاجة إلى توحيد وتوحيد المعرفة المكتسبة.

تعريف

عليك أولاً أن تقرر ما هو REST. تقدم ويكيبيديا الإجابة التالية على هذا السؤال. استراحة (نقل الدولة التمثيلية- "نقل حالة العرض التقديمي") هو أسلوب معماري للتفاعل بين مكونات التطبيق الموزع على الشبكة. REST عبارة عن مجموعة متسقة من القيود التي يتم أخذها في الاعتبار عند تصميم نظام الوسائط التشعبية الموزع.

بكلماتي الخاصة، أود أن أشرح مفهوم REST على أنه "مجموعة من التوصيات التي تسمح لك بتوحيد التفاعل بين تطبيقات العميل والخادم".
سأحاول في هذه المقالة التحدث عن هذه "التوصيات" ذاتها التي ستساعدك على تصميم وإنشاء خدمات REST وفقًا للممارسات المقبولة عمومًا.

تحتاج أيضًا إلى فهم ماهية خدمة REST. أود تعريف خدمة REST بأنها "نقطة التفاعل بين تطبيق العميل والخادم". في مصطلحات Java، هذا عبارة عن servlet الذي يرسل العميل طلبًا إليه.

مشاكل

ولكن قبل أن أبدأ في وصف القواعد، أود أن أنقل فكرة أن REST ليس معيارًا، وبالتالي لا توجد قواعد صارمة واحدة يجب اتباعها. وهذا يعني أنه لا يوجد حتى الآن اتفاق كامل حول الحلول الأفضل لتطبيقها في موقف معين. في كثير من الأحيان تكون هناك مناقشات حول طرق HTTP التي يجب استخدامها وأي رمز HTTP يجب إرجاعه في كل موقف محدد.

اسم الخدمة

أولاً، عليك اختيار اسم لخدمة REST. بواسطة اسم الخدمة أعني مسارها في URI للطلب. على سبيل المثال، http://my-site.by/api/rest/service/name. لاختيار اسم، نحتاج إلى فهم ما هي "الموارد" الموجودة في بنية REST.

عرض الموارد

في مصطلحات REST، يمكن لأي شيء أن يكون موردًا - مستند HTML، أو صورة، أو معلومات حول مستخدم معين، وما إلى ذلك. إذا كان المورد عبارة عن كائن ما، فمن السهل تمثيله باستخدام بعض التنسيقات القياسية، مثل XML أو JSON. بعد ذلك، يمكن للخادم إرسال هذا المورد باستخدام التنسيق المحدد، ويمكن للعميل العمل مع المورد المستلم من الخادم باستخدام نفس التنسيق.

مثال على تمثيل موارد "الملف الشخصي" بتنسيق JSON:

    "المعرف": 1،

    "الاسم":"ماهيش"،

    "تسجيل الدخول" :"مانيش"

لا يضع REST أي قيود صريحة على التنسيق الذي يجب استخدامه لتمثيل الموارد، ولكن هناك عدد من القواعد التي يجب اتباعها عند تصميم التنسيق الذي سيتم استخدامه لتمثيل المورد:

  • يجب على العميل والخادم "فهم" التنسيق المحدد والقدرة على العمل معه.
  • يمكن وصف المورد بشكل كامل باستخدام التنسيق المختار، بغض النظر عن مدى تعقيد المورد.
  • يجب أن يوفر التنسيق القدرة على تمثيل العلاقات بين الموارد.

مثال على تمثيل مورد "الطلب" وارتباطه بمورد "الملف الشخصي":

    الرقم التعريفي: 11254,

    العملة: "يورو"،

    المبلغ: 100

    حساب تعريفي: (

    المعرف: 11,

    أوري: "http://MyService/Profiles/11"

كما ترون، ليس من الضروري تكرار البنية الكاملة للمورد المشار إليه بواسطة مورد آخر. بدلاً من ذلك، يمكنك استخدام رابط واضح لمورد آخر.

الوصول إلى أحد الموارد

يجب أن يتم تعريف كل مورد بشكل فريد بواسطة معرف ثابت. "مستمر" يعني أن المعرف لن يتغير أثناء الاتصال، وحتى عندما تتغير حالة المورد. إذا تم تعيين معرف مختلف للمورد، فيجب على الخادم إبلاغ العميل بأن الطلب لم ينجح وتوفير رابط إلى العنوان الجديد. يتم تعريف كل مورد بشكل فريد بواسطة عنوان URL. وهذا يعني أن عنوان URL هو في الأساس المفتاح الأساسي لعنصر البيانات. وهذا هو، على سبيل المثال، سيبدو الكتاب الثاني من رف الكتب /كتب/2 ، و 41 صفحة في هذا الكتاب - /كتب/2/صفحات/41 . من هنا نحصل على تنسيق محدد بدقة. علاوة على ذلك، لا يهم على الإطلاق التنسيق الذي توجد به البيانات على العنوان /كتب/2/صفحات/41 - يمكن أن يكون هذا بتنسيق HTML، أو نسخة ممسوحة ضوئيًا على شكل ملف jpeg، أو مستند Word.

يوصى باستخدام أسماء الموارد الجمع عند تحديد اسم خدمة REST. يسمح لك هذا الأسلوب بإضافة خدمات REST جديدة فقط من خلال توسيع أسماء الخدمات الموجودة. على سبيل المثال، الخدمة /كتب سيعيد لنا قائمة بجميع الكتب، /كتب/3 سيعود معلومات حول الكتاب الثالث والخدمة /كتب/3/صفحات سيعود جميع صفحات الكتاب الثالث.

بالنسبة للخدمات التي تنفذ بعض الإجراءات المحددة على أحد الموارد، هناك طريقتان لتحديد الإجراء: في اسم الخدمة أو في معلماتها. على سبيل المثال، /books/3/clean أو /books/3?clean . أفضّل الخيار الأول، نظرًا لأن هذه الخدمات عادةً ما تستخدم أساليب POST التي لا تدعم تمرير المعلمات إلى عنوان URL، مما يجعل الخدمة، في رأيي، غير قابلة للقراءة بشكل كبير. من خلال تحديد نوع الإجراء في اسم الخدمة، نجعل خدمتنا أكثر قابلية للتوسيع لأنها لا تعتمد على نوع طريقة HTTP.

لا يُنصح أيضًا بشدة باستخدام الأسماء التي تتضمن عدة كلمات وتصف مكون الأعمال الخاص بالخدمة (كما هو موصى به عند تسمية أساليب جافا). على سبيل المثال، بدلا من /getAllCars من الأفضل أن تصنع طريقة /سيارات . إذا لم يكن من الممكن وصف الطريقة بأي شكل من الأشكال في كلمة واحدة، فمن الضروري استخدام نمط محدد واحد، وعادةً ما أستخدم "-"، وهو الأسلوب الأكثر شيوعًا. على سبيل المثال، /سيارات/3/يمكن بيعها.

يمكنك قراءة المزيد حول تصميم أسماء خدمات REST في

طرق HTTP

يستخدم REST 4 طرق HTTP رئيسية: GET، POST، PUT، DELETE. في معظم الحالات، يتم استخدام كل أسلوب لتنفيذ إجراء محدد مسبقًا من CRUD ( جرد, صإياد, شتاريخ, د elete - "إنشاء، قراءة، تحديث، حذف").
نشر - إنشاء، الحصول على - قراءة، وضع - تحديث، حذف - حذف.

إضافة هامة: هناك ما يسمى بأنماط REST، والتي تختلف في ربط أساليب HTTP بما تفعله. على وجه الخصوص، تتعامل الأنماط المختلفة مع POST وPUT بشكل مختلف. ومع ذلك، فإن المقصود من PUT هو الإنشاء أو الاستبدال أو التحديث؛ ولم يتم تحديد ذلك بالنسبة لـ POST (عملية POST عامة جدًا ولا يمكن ربط أي معنى محدد بها). ولذلك، في بعض الأحيان يمكن تبديل POST وPUT. ولكن في معظم الحالات، يتم استخدام POST للإنشاء، ويتم استخدام PUT للتحرير، وبعد قليل سأشرح السبب.

سأقدم عدة أمثلة لاستخدام أساليب مختلفة للتفاعل مع الموارد.

  • الحصول على /الكتب/- يحصل على قائمة بجميع الكتب. كقاعدة عامة، هذه قائمة مبسطة، أي. يحتوي فقط على معرف الكائن وحقول الاسم، دون بيانات أخرى.
  • الحصول على / الكتب / (المعرف)- يتلقى معلومات كاملة عن الكتاب.
  • مشاركة /كتب/- إنشاء كتاب جديد. يتم إرسال البيانات في نص الطلب.
    وضع /كتب/(معرف)- تغيير البيانات حول كتاب بمعرف (معرف)، وربما استبداله. ويتم إرسال البيانات أيضًا في نص الطلب.
  • الخيارات / الكتب– الحصول على قائمة العمليات المدعومة للمورد المحدد (غير مستخدم عمليا)
  • حذف /الكتب/(المعرف)- حذف البيانات ذات المعرف (المعرف).

الأمن والعجز

إن المعرفة حول أمان هذه الأساليب وعجزها ستساعد بشكل كبير في اختيار طريقة HTTP.

الطلب الآمن هو طلب لا يغير حالة التطبيق.

الاستعلام غير الفعال هو استعلام يكون تأثيره عند تنفيذه عدة مرات مساوياً للتأثير عند تنفيذه مرة واحدة.

بناءً على هذا الجدول، يجب ألا يغير طلب GET حالة المورد الذي يتم تطبيقه عليه. يمكن لطلبات PUT وDELETE تغيير حالة المورد، ولكن يمكن تكرارها بأمان إذا لم تكن متأكدًا من اكتمال الطلب السابق. من حيث المبدأ، هذا أمر منطقي: إذا قمت بتكرار طلب حذف أو استبدال مورد معين بشكل متكرر، فستكون النتيجة إزالة المورد أو استبداله. لكن طلب POST، كما نرى من الجدول، غير آمن وغير عاجز. وهذا يعني أنه لا يغير حالة المورد فحسب، بل إن تكراره المتكرر سيؤدي إلى تأثير يعتمد على عدد التكرارات. ويتوافق معناها مع عملية إضافة عناصر جديدة إلى قاعدة البيانات: تم تنفيذ الاستعلام X مرات، وتمت إضافة عناصر X إلى قاعدة البيانات.

سأقدم أيضًا مثالاً على سبب عدم ضرورة تغيير طلبات GET لحالة المورد. يمكن تخزين طلبات GET مؤقتًا، على سبيل المثال، على مستوى الخادم الوكيل. في هذه الحالة، قد لا يصل الطلب حتى إلى خادم التطبيق، وسيقوم الخادم الوكيل بإرجاع المعلومات من ذاكرة التخزين المؤقت كاستجابة.

رموز HTTP

يصف معيار HTTP أكثر من 70 رمز حالة. من الممارسات الجيدة استخدام الأساسيات على الأقل.

  • 200 - موافق - طلب ناجح. إذا طلب العميل أي بيانات، فسيتم العثور عليها في رأس و/أو نص الرسالة.
  • 201 - حسنًا - نتيجة التنفيذ الناجح للطلب، تم إنشاء مورد جديد.
  • 204 - حسنًا - تم حذف المورد بنجاح.
  • 304 - غير معدل - يمكن للعميل استخدام البيانات من ذاكرة التخزين المؤقت.
  • 400 - طلب سيء - الطلب غير صالح أو لا يمكن معالجته.
  • 401 - غير مصرح به - يتطلب الطلب مصادقة المستخدم.
  • 403 - محظور - لقد فهم الخادم الطلب، لكنه يرفض معالجته أو تم رفض الوصول.
  • 404 - لم يتم العثور عليه - لم يتم العثور على المورد.
  • 500 - خطأ داخلي في الخادم - يجب على مطوري واجهة برمجة التطبيقات (API) محاولة تجنب مثل هذه الأخطاء.

يجب اكتشاف هذه الأخطاء في كتلة الالتقاط العامة، وتسجيلها، ولكن لا ينبغي إرجاعها في الاستجابة.

كلما كانت مجموعة الرموز التي نستخدمها أكثر شمولاً، أصبحت واجهة برمجة التطبيقات (API) التي نقوم بإنشائها أكثر قابلية للفهم. ومع ذلك، عليك أن تأخذ في الاعتبار أن المتصفحات تعالج بعض الرموز بشكل مختلف. على سبيل المثال، تقوم بعض المتصفحات، بعد تلقي رمز الاستجابة 307، بإعادة التوجيه على الفور، بينما يسمح لك البعض الآخر بمعالجة هذا الموقف وإلغاء الإجراء. قبل استخدام أي رمز، عليك أن تفهم تمامًا كيف ستتم معالجته من جانب العميل!

الرؤوس

  • نوع المحتوى- تنسيق الطلب؛
  • يقبل- قائمة تنسيقات الاستجابة.

خيارات البحث عن الموارد

لتبسيط استخدام الخدمات المسؤولة عن إرجاع أي معلومات، بالإضافة إلى جعلها أكثر إنتاجية، من الضروري استخدام معلمات الفرز والتصفية واختيار الحقل وترقيم الصفحات كمعلمات استعلام.

الترشيح

استخدم معلمة استعلام فريدة لكل حقل لتنفيذ التصفية. سيؤدي هذا إلى الحد من كمية المعلومات المعروضة، مما سيؤدي إلى تحسين وقت معالجة الطلب.

على سبيل المثال، لعرض كافة الكتب الحمراء، تحتاج إلى تشغيل الاستعلام التالي:

الحصول على / الكتب؟ اللون = أحمر

فرز

يتم تنفيذ الفرز بشكل مشابه للتصفية. على سبيل المثال، لعرض جميع الكتب مرتبة حسب سنة النشر بترتيب تنازلي وحسب العنوان بترتيب تصاعدي، تحتاج إلى تشغيل الاستعلام التالي:

الحصول على /books?sort=-year,+name

ترقيم الصفحات

من أجل دعم القدرة على تحميل قائمة الموارد التي يجب عرضها على صفحة تطبيق معينة، يجب أن توفر REST API وظيفة ترقيم الصفحات. يتم تنفيذه باستخدام معلمات الحد والإزاحة المألوفة لنا من SQL. على سبيل المثال:

احصل على /books?offset=10&limit=5

بالإضافة إلى ذلك، من الممارسات الجيدة عرض الروابط إلى الصفحات السابقة والتالية والأولى والأخيرة في رأس الرابط. على سبيل المثال:

وصلة: ; ريل = "التالي"،
; ريل = "الأخير"،
; ريل = "أولا"،
; ريل = "السابق"

اختيار حقول الموارد

لاستخدام أكثر ملاءمة للخدمة، لحفظ حركة المرور، يمكنك توفير القدرة على التحكم في تنسيق إخراج البيانات. يتم تنفيذه من خلال توفير القدرة على تحديد حقول الموارد التي يجب أن ترجعها خدمة REST. على سبيل المثال، إذا كنت تريد الحصول على معرفات الكتب وألوانها فقط، فستحتاج إلى تشغيل الاستعلام التالي:

الحصول على /books?fields=id,color

تخزين الدولة

أحد القيود المفروضة على خدمات RESTful هو أنها لا تحتاج إلى تخزين حالة العميل الذي تتلقى الطلبات منه.

مثال على خدمة عديمة الجنسية:
الطلب1:
الطلب2: احصل على http://MyService/Persons/2 HTTP/1.1

ويمكن معالجة كل من هذه الطلبات بشكل مستقل عن الآخر.

مثال على خدمة تخزن الحالة:
الطلب1: احصل على http://MyService/Persons/1 HTTP/1.1
الطلب2: احصل على http://MyService/NextPerson HTTP/1.1

لمعالجة الطلب الثاني، سيحتاج الخادم إلى "تذكر" معرف آخر شخص طلبه العميل. أولئك. يجب أن "يتذكر" الخادم حالته الحالية، وإلا فلن تتمكن من معالجة الطلب الثاني. عند تصميم خدمة، يجب عليك تجنب الحاجة إلى تخزين الحالة، حيث أن ذلك له عدد من المزايا.

فوائد خدمة عديمي الجنسية:

  • تقوم الخدمة بمعالجة الطلبات بشكل مستقل عن بعضها البعض؛
  • تم تبسيط بنية الخدمة؛
  • لا يلزم بذل أي جهد إضافي لتنفيذ الخدمات باستخدام بروتوكول HTTP، وهو أيضًا عديم الحالة.

عيوب الخدمة عديمة الجنسية:

  • يجب أن يكون العميل نفسه مسؤولاً عن تمرير السياق اللازم إلى الخدمة.

الإصدار

من الممارسات الجيدة دعم إصدار REST API. سيسمح لك هذا بتوسيع واجهة برمجة التطبيقات (API) بسهولة في المستقبل، دون الحاجة إلى إجراء تغييرات بالضرورة على العملاء الذين يستخدمونها بالفعل.
هناك عدة طرق لتنفيذ الإصدار:

  • باستخدام قبول الرأس. في هذه الحالة، تتم الإشارة إلى إصدار API في قبول - قبول: نص/v2+json
  • باستخدام URI. في هذا الأسلوب، يتم تحديد إصدار واجهة برمجة التطبيقات مباشرة في URI - http://localhost/api/v2/books
  • باستخدام رأس مخصص. يمكنك استخدام رأسك الخاص، والذي سيكون مسؤولاً فقط عن تمرير إصدار API - إصدار واجهة برمجة التطبيقات: v2
  • باستخدام معلمة الاستعلام. يمكنك استخدام معلمة استعلام لتمرير إصدار API - /كتب?v=2

كل من الأساليب المقدمة لها الحق في الوجود، ولكل منها إيجابيات وسلبيات خاصة بها. ومع ذلك، الأمر متروك لك لتحديد طريقة تنفيذ الإصدار المناسبة لمشروعك.

توثيق

للاستخدام المريح لخدمات REST الخاصة بنا، تحتاج إلى إنشاء وثائق جيدة ومفهومة. يمكنك استخدام أدوات مختلفة لهذه الأغراض، مثل Mashape أو Apiary، لكنني أوصي باستخدام Swagger.

Swagger هي تقنية تسمح لك بتوثيق خدمات REST. يدعم Swagger العديد من لغات وأطر البرمجة. بالإضافة إلى ذلك، يوفر Swagger واجهة مستخدم لعرض الوثائق.

يمكنك الحصول على معلومات أكثر تفصيلاً حول Swagger هنا.

الأرشفة

التخزين المؤقت

أيضًا، لتقليل الاستعلامات إلى قاعدة البيانات وزيادة أداء خدمات REST الخاصة بنا، يوصى باستخدام آلية التخزين المؤقت. يمكن تكوين التخزين المؤقت على مستوى الخادم وفي التطبيق نفسه، اعتمادًا على الموقف.

يمكن التحكم في التخزين المؤقت باستخدام رؤوس HTTP التالية:

  • التاريخ - تاريخ ووقت إنشاء المورد.
  • آخر تعديل - تاريخ ووقت آخر تعديل للمورد على الخادم.
  • التحكم في ذاكرة التخزين المؤقت - يستخدم رأس HTTP 1.1 للتحكم في ذاكرة التخزين المؤقت.
  • العمر - الوقت المنقضي منذ آخر استلام للمورد، يمكن إضافة الرأس بواسطة مكون وسيط (بين العميل والخادم) (على سبيل المثال، خادم وكيل)

هذه التدوينة عبارة عن إجابة لسؤال تم طرحه في تعليق على إحدى مقالاتي.

في هذه المقالة أريد أن أخبرك ما هي طرق HTTP GET/POST/PUT/DELETE وغيرها، ولماذا تم اختراعها وكيفية استخدامها وفقًا لـ REST.

HTTP

إذًا، ما هو أحد البروتوكولات الرئيسية للإنترنت؟ سأرسل الأطفال إلى RFC2616، وسأخبر الباقي بشكل إنساني :)

يصف هذا البروتوكول التفاعل بين جهازي كمبيوتر (العميل والخادم)، المبني على أساس رسائل تسمى الطلب (Request) والاستجابة (Response). تتكون كل رسالة من ثلاثة أجزاء: سطر البداية، والعناوين، والنص. في هذه الحالة، مطلوب فقط خط البداية.

تحتوي خطوط البداية للطلب والاستجابة على تنسيقات مختلفة - نحن مهتمون فقط بسطر بداية الطلب، والذي يبدو كما يلي:

طريقة URI HTTP/ إصدار ,

حيث METHOD هي طريقة طلب HTTP، وURI هو معرف المورد، وVERSION هو إصدار البروتوكول (الإصدار 1.1 حاليًا هو الحالي).

الرؤوس عبارة عن مجموعة من أزواج الاسم والقيمة مفصولة بنقطتين. تنقل الرؤوس معلومات الخدمة المتنوعة: تشفير الرسالة، واسم المتصفح وإصداره، والعنوان الذي جاء منه العميل (المُحيل)، وما إلى ذلك.

نص الرسالة هو البيانات الفعلية التي يتم إرسالها. في الاستجابة، البيانات المرسلة، كقاعدة عامة، هي صفحة HTML التي طلبها المتصفح، وفي الطلب، على سبيل المثال، في نص الرسالة، يتم نقل محتويات الملفات التي تم تحميلها إلى الخادم. ولكن كقاعدة عامة، لا يوجد نص رسالة في الطلب على الإطلاق.

مثال على تفاعل HTTP

لنلقي نظرة على مثال.

طلب:
احصل على /index.php HTTP/1.1 المضيف: example.com وكيل المستخدم: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5 قبول: نص/html الاتصال: إغلاق
السطر الأول هو سطر الاستعلام، والباقي عبارة عن رؤوس؛ نص الرسالة مفقود

إجابة:
HTTP/1.0 200 OK الخادم: nginx/0.6.31 لغة المحتوى: ru نوع المحتوى: نص/html; charset=utf-8 طول المحتوى: 1234 الاتصال: إغلاق... صفحة HTML نفسها...

الموارد والأساليب

دعنا نعود إلى سطر البداية للطلب ونتذكر أنه يحتوي على معلمة مثل URI. يشير هذا إلى معرف المورد الموحد - معرف المورد الموحد. المورد، كقاعدة عامة، هو ملف على الخادم (مثال URI في هذه الحالة هو "/styles.css")، ولكن بشكل عام يمكن أن يكون المورد أيضًا كائنًا مجردًا ("/blogs/webdev/" - نقاط إلى تطوير كتلة "الويب" بدلاً من ملف محدد).

يخبر نوع طلب HTTP (يسمى أيضًا طريقة HTTP) الخادم بالإجراء الذي نريد تنفيذه على المورد. في البداية (في أوائل التسعينيات) كان من المفترض أن العميل قد يريد شيئًا واحدًا فقط من المورد - لتلقيه، ولكن الآن باستخدام بروتوكول HTTP، يمكنك إنشاء منشورات وتحرير ملف تعريف وحذف الرسائل وغير ذلك الكثير. ومن الصعب الجمع بين هذه الإجراءات ومصطلح "الإيصال".

للتمييز بين الإجراءات والموارد على مستوى أساليب HTTP، تم اختراع الخيارات التالية:

  • الحصول على - الحصول على الموارد
  • ما بعد - إنشاء الموارد
  • وضع - تحديث الموارد
  • حذف - حذف مورد
يرجى ملاحظة أن مواصفات HTTP لا تتطلب من الخادم فهم جميع الطرق (التي يوجد منها في الواقع أكثر من 4 طرق) - مطلوب GET فقط، كما أنه لا يخبر الخادم بما يجب عليه فعله عند تلقي طلب باستخدام محدد معين. طريقة. وهذا يعني أن الخادم يستجيب لطلب DELETE /index.php HTTP/1.1 غير ملزم بذلكاحذف صفحة Index.php الموجودة على الخادم، كما هو الحال بالنسبة لطلب GET /index.php HTTP/1.1 غير ملزم بذلكيرجع لك صفحة Index.php ممكن يحذفها مثلا :)

REST يأتي دوره

REST (نقل الحالة التمثيلية) هو مصطلح تمت صياغته في عام 2000 بواسطة Roy Fielding، أحد مطوري بروتوكول HTTP، كاسم لمجموعة مبادئ لبناء تطبيقات الويب. بشكل عام، يغطي REST مساحة أكبر من HTTP - ويمكن استخدامه أيضًا في شبكات أخرى مع بروتوكولات أخرى. تصف REST مبادئ التفاعل بين العميل والخادم، بناءً على مفاهيم "المورد" و"الفعل" (يمكن فهمها على أنها موضوع ومسند). في حالة HTTP، يتم تعريف المورد من خلال URI الخاص به، والفعل هو طريقة HTTP.

يقترح REST التخلي عن استخدام نفس URI لموارد مختلفة (أي عناوين مقالتين مختلفتين مثل /index.php?article_id=10 و /index.php?article_id=20 - هذه ليست طريقة REST) ​​و باستخدام طرق HTTP مختلفة لإجراءات مختلفة. أي أن تطبيق الويب المكتوب باستخدام نهج REST سيحذف المورد عند الوصول إليه باستخدام طريقة HTTP DELETE (بالطبع، هذا لا يعني أنه من الضروري إتاحة الفرصة لحذف كل شيء وكل شخص، ولكن أييجب أن يستخدم طلب الحذف الخاص بالتطبيق طريقة HTTP DELETE).

يمنح REST المبرمجين القدرة على كتابة تطبيقات ويب موحدة وأجمل قليلاً من ذي قبل. باستخدام REST، لن يكون URI لإضافة مستخدم جديد هو /user.php?action=create (أسلوب GET/POST)، ولكن ببساطة /user.php (أسلوب POST فقط).

ونتيجة لذلك، من خلال الجمع بين مواصفات HTTP الحالية ونهج REST، تصبح طرق HTTP المختلفة منطقية في النهاية. GET - يُرجع موردًا، POST - يُنشئ موردًا جديدًا، PUT - يُحدث موردًا موجودًا، DELETE - يحذفه.

مشاكل؟

نعم، هناك مشكلة صغيرة في استخدام REST عمليًا. هذه المشكلة تسمى HTML.

يمكن إرسال طلبات PUT/DELETE باستخدام XMLHttpRequest، عن طريق الاتصال بالخادم يدويًا (على سبيل المثال، عبر curl أو حتى عبر telnet)، ولكن لا يمكنك إنشاء نموذج HTML يرسل طلب PUT/DELETE كاملاً.

المشكلة هي أن مواصفات HTML لا تسمح لك بإنشاء نماذج ترسل بيانات بخلاف GET أو POST. لذلك، للعمل بشكل طبيعي مع الطرق الأخرى، عليك تقليدها بشكل مصطنع. على سبيل المثال، في Rack (الآلية التي على أساسها تتفاعل Ruby مع خادم الويب؛ يتم إنشاء Rails وMerb وأطر عمل Ruby الأخرى باستخدام Rack)، يمكنك إضافة حقل مخفي إلى النموذج بالاسم "_method"، و حدد اسم الطريقة كقيمة (على سبيل المثال، "PUT") - في هذه الحالة، سيتم إرسال طلب POST، لكن سيكون بإمكان Rack التظاهر بأنه تلقى PUT بدلاً من POST.

يمكن إنشاء RESTful API ليس فقط لخدمات الجهات الخارجية. يمكن استخدامه من خلال تطبيقات الصفحة الواحدة للعمل الخلفي. فيما يلي بعض الأشياء الأساسية التي يجب معرفتها عند تصميم الواجهة.

عناوين URL والإجراءات

أحد المبادئ الأساسية لـ REST هو تقسيم واجهة برمجة التطبيقات (API) الخاصة بك إلى موارد منطقية. تتم إدارة هذه الموارد باستخدام طلبات HTTP بالطريقة المناسبة - GET، POST، PUT، PATCH، DELETE.

يجب أن يتم وصف المورد بصيغة الجمع. عادةً ما يتم تحديد الإجراءات على الموارد من خلال استراتيجية CRUD وتتوافق مع أساليب HTTP على النحو التالي:

  • الحصول على /api/users - الحصول على قائمة المستخدمين؛
  • الحصول على /api/users/123 - الحصول على المستخدم المحدد؛
  • POST /api/users - إنشاء مستخدم جديد؛
  • PUT /api/users/123 - تحديث جميع بيانات المستخدم المحدد؛
  • PATCH /api/users/123 - تحديث بيانات المستخدم جزئيًا؛
  • حذف /api/users/123 - حذف مستخدم.

إذا كان المورد موجودًا فقط في سياق مورد آخر، فقد يكون عنوان URL معقدًا:

  • الحصول على /api/posts/9/comments - الحصول على قائمة التعليقات للمنشور رقم 9؛
  • احصل على /api/posts/9/comments/3 - احصل على التعليق رقم 3 للمشاركة رقم 9.

عندما لا يتوافق الإجراء الذي يتم تنفيذه على كائن ما مع عملية CRUD، فيمكن اعتباره موردًا مركبًا:

  • POST /api/posts/9/like - قم بوضع علامة على المنشور رقم 9 كما تم الإعجاب به؛
  • حذف /api/posts/9/like - إزالة علامة "أعجبني" من المشاركة رقم 9.

يجب أن تؤدي إجراءات إنشاء الموارد وتحديثها إلى إرجاع مورد

يمكن لطرق POST أو PUT أو PATCH تعديل حقول الموارد التي لم يتم تضمينها في الطلب (على سبيل المثال، المعرف أو تاريخ الإنشاء أو تاريخ التحديث). لتجنب إجبار مستخدم واجهة برمجة التطبيقات (API) على تقديم طلب آخر للحصول على البيانات المحدثة، يجب أن تعيد هذه الطرق هذه البيانات في الاستجابة.

المرشحات والفرز والبحث

يمكن استخدام أي معلمات في طلب HTTP لتحسين الطلب أو فرز البيانات.

  • الحصول على /api/users?state=active - قائمة المستخدمين النشطين؛
  • الحصول على /api/tasks?state=open&sort=priority,-created_at - قائمة بالمهام المعلقة، مرتبة حسب الأولوية وتاريخ الإنشاء (المهام الجديدة أولاً).

التنقل في الصفحة

عندما تحتاج إلى إضافة معلومات حول التنقل في الصفحة استجابةً لطلب قائمة الكائنات، يجب عليك استخدام رأس Link HTTP بدلاً من إضافة أغلفة البيانات.

مثال على الرأس:

وصلة: ; ريل = "التالي"، ; ريل = "السابق"، ; ريل = "أولا"، ; ريل = "الأخير"

القيم المحتملة لـ rel:

  • التالي - الصفحة التالية من النتائج؛
  • السابق - الصفحة السابقة للنتائج؛
  • الأولى - الصفحة الأولى من النتائج؛
  • الأخيرة - الصفحة الأخيرة من النتائج.

من المهم اتباع هذه القيم بدلاً من إنشاء عناوين URL الخاصة بك، لأنه في بعض الأحيان قد يعتمد التنقل بين الصفحات على قواعد معقدة بدلاً من مجرد التكرار عبر الصفحات.

تجاوز أسلوب HTTP

للتوافق مع بعض الخوادم أو العملاء الذين لا يدعمون أساليب HTTP بخلاف GET وPOST، قد تكون محاكاتها مفيدة. يتم تمرير قيمة الطريقة في رأس X-HTTP-Method-Override، ويتم تنفيذ الطريقة نفسها كطريقة POST. يجب ألا تغير طلبات GET حالة الخادم!

رموز حالة HTTP

  • 200 OK - الاستجابة لطلب GET أو PUT أو PATCH أو DELETE الناجح.
  • 201 تم الإنشاء - استجابة لطلب POST، مما أدى إلى إنشاء كائن جديد. يجب أن تكون الاستجابة أيضًا مصحوبة برأس موقع يشير إلى عنوان URL للمورد.
  • 204 لا يوجد محتوى - استجابة لطلب تم تنفيذه بنجاح ولا يُرجع أي شيء (على سبيل المثال، حذف).
  • 404 لم يتم العثور عليه - لم يتم العثور على الكائن المطلوب.
  • 500 خطأ داخلي في الخادم - خطأ في الخادم.

في حالة وجود أخطاء، قد تحتوي الاستجابة على معلومات تصحيح الأخطاء للمطورين، إن أمكن.