أفضل الممارسات لإنشاء واجهات برمجة تطبيقات REST

مرحبا!



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



استمتع بالقراءة!



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



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



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



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



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



اقبل JSON وأعد JSON ردًا



يجب أن تقبل واجهات برمجة تطبيقات REST JSON لحمولة الطلب وكذلك إرسال استجابات JSON. JSON هو معيار لنقل البيانات. يتم تكييف أي تقنية شبكة تقريبًا لاستخدامها: تحتوي JavaScript على طرق مضمنة لتشفير وفك تشفير JSON ، إما من خلال Fetch API أو من خلال عميل HTTP آخر. تستخدم تقنيات جانب الخادم المكتبات لفك تشفير JSON بتدخل ضئيل أو بدون تدخل من جانبك.



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



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



للتأكد من أن العميل يفسر JSON المستلم من REST API تمامًا مثل JSON ، اضبط عنوان Content-Typeالاستجابة على قيمة application/jsonبعد تقديم الطلب. تقوم العديد من أطر عمل التطبيقات من جانب الخادم بتعيين رأس الاستجابة تلقائيًا. يبحث بعض عملاء HTTP Content-Typeفي رأس الاستجابة ويحللون البيانات وفقًا للتنسيق المحدد هناك.



الاستثناء الوحيد يحدث عندما نحاول إرسال واستقبال الملفات التي يتم نقلها بين العميل والخادم. ثم تحتاج إلى معالجة الملفات المستلمة كاستجابة وإرسال بيانات النموذج من العميل إلى الخادم. لكن هذا موضوع لمقال آخر.



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



لنأخذ مثالاً لواجهة برمجة تطبيقات تقبل حمولة JSON. يستخدم هذا المثال إطار عمل Express Backend لـ Node.js. يمكننا استخدام برنامج كبرنامج وسيط body-parserلتحليل نص طلب JSON ، ثم استدعاء طريقة res.jsonمع الكائن الذي نريد إرجاعه كاستجابة JSON. يتم ذلك على النحو التالي:



const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());

app.post('/', (req, res) => {
  res.json(req.body);
});

app.listen(3000, () => console.log('server started'));


bodyParser.json()يوزع سلسلة نص الطلب إلى JSON ، ويحولها إلى كائن JavaScript ، ثم يعين النتيجة إلى الكائن req.body.



قم بتعيين رأس نوع المحتوى في الاستجابة لقيمة application/json; charset=utf-8بدون أي تغييرات. الطريقة الموضحة أعلاه قابلة للتطبيق على معظم الأطر الخلفية الأخرى.



نحن نستخدم أسماء للمسارات إلى نقاط النهاية ، وليس الأفعال



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



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



يجب تحديد الإجراء باسم طريقة HTTP للطلب الذي نجريه. تحتوي الطرق الأكثر شيوعًا على الأفعال GET و POST و PUT و DELETE.

الحصول على موارد الجلب. يرسل POST بيانات جديدة إلى الخادم. يقوم PUT بتحديث البيانات الموجودة. حذف يحذف البيانات. كل من هذه الأفعال يتوافق مع إحدى العمليات من مجموعة CRUD .



بالنظر إلى المبدأين اللذين تمت مناقشتهما أعلاه ، من أجل تلقي مقالات جديدة ، يجب علينا إنشاء مسارات من النموذج GET /articles/. وبالمثل ، نستخدم POST /articles/لتحديث مقال جديد ، PUT /articles/:id لتحديث مقال بالمقال المعطى id. تم /articles/:idتصميم طريقة DELETE لحذف مقالة بمعرف معين.



/articlesهو مورد REST API. على سبيل المثال ، يمكنك استخدام Express للقيام بما يلي مع المقالات:



const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());

app.get('/articles', (req, res) => {
  const articles = [];
  //    ...
  res.json(articles);
});

app.post('/articles', (req, res) => {
  //     ...
  res.json(req.body);
});

app.put('/articles/:id', (req, res) => {
  const { id } = req.params;
  //    ...
  res.json(req.body);
});

app.delete('/articles/:id', (req, res) => {
  const { id } = req.params;
  //    ...
  res.json({ deleted: id });
});

app.listen(3000, () => console.log('server started'));


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



تقبل نقاط نهاية POST و PUT و DELETE نص طلب JSON وتعيد استجابة JSON أيضًا ، بما في ذلك نقطة نهاية GET.



تسمى المجموعات أسماء الجمع



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



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



عند العمل بنقطة نهاية ، /articlesنستخدم صيغة الجمع عند تسمية كل نقاط النهاية.



تداخل الموارد عند العمل مع كائنات هرمية



يجب هيكلة مسار نقاط النهاية التي تتعامل مع الموارد المتداخلة على النحو التالي: أضف المورد المتداخل كاسم مسار يتبع اسم المورد الرئيسي.

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



على سبيل المثال ، إذا أردنا تلقي تعليقات على مقال جديد عند نقطة نهاية معينة ، فيجب علينا إرفاق المسار / التعليقات بنهاية المسار /articles. في هذه الحالة ، من المفترض أننا نعتبر كيان التعليقات كيانًا فرعيًا articleفي قاعدة بياناتنا.



على سبيل المثال ، يمكنك القيام بذلك باستخدام الكود التالي في Express:



const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());

app.get('/articles/:articleId/comments', (req, res) => {
  const { articleId } = req.params;
  const comments = [];
  //      articleId
  res.json(comments);
});


app.listen(3000, () => console.log('server started'));


في الكود أعلاه ، يمكنك استخدام طريقة GET على المسار '/articles/:articleId/comments'. نتلقى التعليقات commentsعلى المقالة المطابقة articleId، ثم نعيدها ردًا. نضيف 'comments'بعد مقطع المسار '/articles/:articleId'للإشارة إلى أن هذا مورد تابع /articles.



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



معالجة الأخطاء بدقة وإرجاع رموز الخطأ القياسية



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



أكثر رموز خطأ HTTP شيوعًا هي:



  • 400 طلب غير صحيح - يشير إلى أن الإدخال المتلقاة من العميل فشل في التحقق من الصحة.
  • 401 غير مصرح به - يعني أن المستخدم لم يسجل الدخول وبالتالي ليس لديه إذن للوصول إلى المورد. عادة ، يتم إصدار هذا الرمز عندما لا يتم مصادقة المستخدم.
  • 403 محظور - يشير إلى أن المستخدم تمت مصادقته ولكن غير مصرح له بالوصول إلى المورد.
  • 404 غير موجود - يعني أنه لم يتم العثور على المورد
  • خطأ الخادم الداخلي 500 هو خطأ في الخادم ومن المحتمل ألا يتم طرحه بشكل صريح.
  • 502 Bad Gateway - تشير إلى رسالة رد غير صالحة من الخادم الرئيسي.
  • 503 Service Unavailable - يعني حدوث شيء غير متوقع على جانب الخادم - على سبيل المثال ، التحميل الزائد للخادم ، وفشل بعض عناصر النظام ، وما إلى ذلك.


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



const express = require('express');
const bodyParser = require('body-parser');

const app = express();

//  
const users = [
  { email: 'abc@foo.com' }
]

app.use(bodyParser.json());

app.post('/users', (req, res) => {
  const { email } = req.body;
  const userExists = users.find(u => u.email === email);
  if (userExists) {
    return res.status(400).json({ error: 'User already exists' })
  }
  res.json(req.body);
});


app.listen(3000, () => console.log('server started'));


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



علاوة على ذلك ، إذا حاولنا نقل حمولة بقيمة emailموجودة بالفعل لدى المستخدمين ، فسنحصل على رد برمز 400 ورسالة 'User already exists'تشير إلى وجود هذا المستخدم بالفعل. باستخدام هذه المعلومات ، يمكن للمستخدم أن يتحسن - استبدل عنوان البريد الإلكتروني بالعنوان غير الموجود في القائمة.



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



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



السماح بفرز البيانات وتصفيتها وترقيمها



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



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



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



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



const express = require('express');
const bodyParser = require('body-parser');

const app = express();

//      
const employees = [
  { firstName: 'Jane', lastName: 'Smith', age: 20 },
  //...
  { firstName: 'John', lastName: 'Smith', age: 30 },
  { firstName: 'Mary', lastName: 'Green', age: 50 },
]

app.use(bodyParser.json());

app.get('/employees', (req, res) => {
  const { firstName, lastName, age } = req.query;
  let results = [...employees];
  if (firstName) {
    results = results.filter(r => r.firstName === firstName);
  }

  if (lastName) {
    results = results.filter(r => r.lastName === lastName);
  }

  if (age) {
    results = results.filter(r => +r.age === +age);
  }
  res.json(results);
});

app.listen(3000, () => console.log('server started'));


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



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



بعد القيام بذلك ، نرجع النتائج كرد. ومن ثم ، عند إجراء طلب GET للمسار التالي بسلسلة استعلام:



/employees?lastName=Smith&age=30


نحن نحصل:



[
    {
        "firstName": "John",
        "lastName": "Smith",
        "age": 30
    }
]


كاستجابة تم إرجاعها لأن التصفية كانت في lastNameو age.



وبالمثل ، يمكنك أخذ معلمة استعلام الصفحة وإرجاع مجموعة من السجلات التي تشغل مناصب من (page - 1) * 20إلى page * 20.



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



http://example.com/articles?sort=+author,-datepublished


حيث +تعني "أعلى" و "أسفل". وبالتالي ، فإننا نقوم بالفرز حسب اسم المؤلف أبجديًا وحسب البيانات المنشورة من الأحدث إلى الأقدم.



الالتزام بالممارسات الأمنية المثبتة



يجب أن يكون الاتصال بين العميل والخادم خاصًا في الغالب ، لأننا غالبًا ما نرسل ونتلقى معلومات سرية. ومن ثم ، فإن استخدام SSL / TLS للأمان أمر لا بد منه.



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



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



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



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



بيانات التخزين المؤقت لتحسين الأداء



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



تتوفر مجموعة متنوعة من خيارات التخزين المؤقت ، مثل Redis والتخزين المؤقت في الذاكرة والمزيد. يمكنك تغيير طريقة تخزين البيانات مؤقتًا حسب الحاجة.



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



const express = require('express');

const bodyParser = require('body-parser');
const apicache = require('apicache');
const app = express();
let cache = apicache.middleware;
app.use(cache('5 minutes'));

//      
const employees = [
  { firstName: 'Jane', lastName: 'Smith', age: 20 },
  //...
  { firstName: 'John', lastName: 'Smith', age: 30 },
  { firstName: 'Mary', lastName: 'Green', age: 50 },
]

app.use(bodyParser.json());

app.get('/employees', (req, res) => {
  res.json(employees);
});

app.listen(3000, () => console.log('server started'));


رمز أعلاه تشير ببساطة إلى apicacheمع apicache.middleware، مما أدى إلى:



app.use(cache('5 minutes'))


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



إصدارات API



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



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



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



على سبيل المثال ، إليك كيفية القيام بذلك في Express:



const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());

app.get('/v1/employees', (req, res) => {
  const employees = [];
  //      
  res.json(employees);
});

app.get('/v2/employees', (req, res) => {
  const employees = [];
  //       
  res.json(employees);
});

app.listen(3000, () => console.log('server started'));


نضيف فقط رقم الإصدار إلى بداية المسار المؤدي إلى نقطة النهاية.



خاتمة



تتمثل الفكرة الرئيسية المستفادة من تصميم واجهات برمجة تطبيقات REST عالية الجودة في الحفاظ على الاتساق من خلال اتباع معايير واتفاقيات الويب. تعد أكواد حالة JSON و SSL / TLS و HTTP ضرورية على الويب اليوم.



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



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



All Articles