OOZOU
تواصلوا معنا
العودة إلى المدونة

توحيد معايير واجهات RESTful JSON API باستخدام مواصفة OpenAPI

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

29 يوليو 2020
6 دقائق للقراءة
توحيد معايير واجهات RESTful JSON API باستخدام مواصفة OpenAPI

ما هي مواصفة JSON API؟

لفترة طويلة جدًا، كانت واجهات JSON API تُبنى بهياكل مختلفة تمامًا. فقد تبدو واجهة ما مختلفة كليًا عن الأخرى، وأحيانًا تتشابه في أمور مثل استخدام /api/v1 لتحديد الإصدار، أو هيكلة الـ params بحيث يكون الـ model هو العقدة الجذرية، مثل { base_node: { foo: "bar" } }، لكن التشابه كان يتوقف عند هذا الحد في الغالب. فكل مشروع، وأحيانًا كل فريق، يضع معاييره الخاصة. وفي أسوأ الحالات، يكون لكل endpoint تنسيقه الخاص. هذا التشتت مكلف، أما مع وجود مواصفة موحدة فنعرف ما نتوقعه من كل endpoint في أي تطبيق. وهذا يتيح لنا بناء معرفة قابلة للنقل بين المشاريع، ومكتبات توفّر الوقت وتقلّل الأخطاء. في عام 2013 قرر Yehuda Katz أن يجرّب صياغة مواصفة لواجهات JSON API. وقد استُخلصت المسودة الأولى من طريقة نقل JSON التي كان يعرّفها ضمنيًا الـ REST adapter في Ember Data. ووصلت المواصفة إلى الإصدار المستقر 1.0 في مايو 2015، ومنذ ذلك الحين يتناقشها مساهمون كثيرون ويتواصل تطويرها بوتيرة ثابتة. ونأمل أن تصل المواصفة قريبًا إلى الإصدار v1.1، ويمكنكم الاطلاع على التغييرات هنا https://jsonapi.org/#update-history

البداية

يجب إرسال جميع الطلبات مع الترويستين Content-Type و_Accepts_ بنوع MIME التالي: application/vnd.api+json ولإنشاء مورد (resource) جديد، نرسل طلب POST يتضمن مستند json بالتنسيق التالي.

{
  "data": {
    "type": "foo",
    "attributes": {
      "title": "Foo resource",
      "url": "https://example.com/bar.html"
    },
    "relationships": {
      "bar": {
        "data": {
          "type": "bar",
          "id": "9"
        }
      }
    }
  }
}

كما ترون، يتضمن المستند عقدة data في الجذر تعرّف كائن مورد واحدًا. ويحدّد كائن المورد النوع (type) والسمات (attributes) والعلاقات (relationships). ويمكننا بعد ذلك استخدام هذه المعلومات في الـ backend لإنشاء الكائن الصحيح في قاعدة البيانات. وعند إنشاء مورد، يمكن للعميل تقديم UUID في الحقل data.attributes.id لتحديد المعرّف (ID) الخاص بالمورد الجديد. حاليًا يُسمح بعملية واحدة فقط في كل طلب، لكن هناك نقاشات حول طريقة دعم عمليات متعددة في الطلب الواحد مستقبلًا، ما سيتيح لنا إنشاء العلاقات في الوقت نفسه الذي ننشئ فيه المورد. وسيُضاف ذلك في الإصدارات القادمة من المواصفة. وتحدّد المواصفة أيضًا بعض القواعد حول كيفية تنسيق الاستجابات لطلباتنا. إذا أُنشئ المورد بنجاح وكان العميل قد قدّم معرّفًا، يمكننا إرجاع استجابة 204 No Content، وهذا يقلّل حجم البيانات المتبادلة. أما إذا أُنشئ المورد بنجاح دون تقديم معرّف، فيجب أن نرجع 201 مع ترويسة Location ومستند يحتوي على المورد الذي أُنشئ للتو، مثل:

HTTP/1.1 201 Created
Location: https://example.com/foos/ddf358c2-a0fb-4035-946d-4b8f96ea334b
Content-Type: application/vnd.api+json
{
  "data": {
    "type": "foo",
    "id": "ddf358c2-a0fb-4035-946d-4b8f96ea334b",
    "attributes": {
      "title": "Foo resource",
      "url": "https://example.com/bar.html"
    },
    "links": {
      "self": "https://example.com/foos/ddf358c2-a0fb-4035-946d-4b8f96ea334b"
    }
  }
}

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

جلب الموارد والعلاقات

الفرق الوحيد بين استجابة المورد الفردي واستجابة المجموعة هو محتوى عقدة data. فالـ endpoints الخاصة بالمجموعات ترجع مصفوفة من كائنات الموارد، بينما ترجع الـ endpoint الفردية كائن مورد واحدًا، مثل:

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    }
  }
}

مقابل

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "related": "https://example.com/articles/1/author"
        }
      }
    }
  }, {
    "type": "articles",
    "id": "2",
    "attributes": {
      "title": "Rails is Omakase"
    },
    "relationships": {
      "author": {
        "links": {
          "related": "https://example.com/articles/1/author"
        }
      }
    }
  }]
}

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

تضمين العلاقات

لتضمين علاقة، نحتاج إلى تمرير قائمة العلاقات التي نريد إرجاعها في الـ query params عند إرسال الطلب، مثل:

/articles/1?include=authors

سيُرجع هذا العلاقة بتنسيق مختلف قليلًا:

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "Lorem ipsum",
      "published-at": "2020-20-01T00:00:00+7:00"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      }
    }
  },
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }]
}

قد يبدو هذا مبالغًا فيه مع مورد واحد، لكن عندما ترجعون 30 سجلًا تتشارك الكثير من البيانات، فإنه يقلّل حجم البيانات المتبادلة بشكل ملحوظ. كما يمنح هذا الأسلوب العميل تحكمًا أكبر بكثير في تحديد ما يريده بالضبط.

السماح للعملاء بطلب جزء من الحقول عبر sparse fieldsets

تعرّف مواصفة JSON API أيضًا آلية تتيح للعميل تقليل عدد الحقول التي تُرجع لكل مورد. ولطلب sparse fieldset، يمكننا تمرير الحقول عبر الـ query parameters مرة أخرى، بل يمكننا تمريرها للعلاقات أيضًا:

/articles?include=author&fields[articles]=title,body&fields[people]=name

سيُرجع هذا الطلب ما يلي:

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "Lorem ipsum",
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      }
    }
  },
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "name": "D. Gebhardt"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }]
}

الخلاصة

لم يتناول هذا المقال إلا القليل مما تعرّفه المواصفة. وهي تستحق فعلًا أن تطّلعوا عليها، فهي تغطي ترقيم الصفحات (pagination)، وتنسيق الأخطاء، وأنواع الاستجابات، وإنشاء الموارد وتحديثها، وترتيب النتائج، وغير ذلك الكثير. يمكنكم قراءة المواصفة كاملة على الموقع الرسمي https://jsonapi.org/ تتبنى شركات أكثر فأكثر مواصفة JSON API. فقد طوّرت Netflix مكتبة fast_jsonapi وأتاحتها لمجتمع المصادر المفتوحة. وهناك أيضًا gems أخرى كثيرة، فمكتبة active_model_serializers تدعم الآن مواصفة JSON API. وآمل أن تتبنى شركات أكثر هذه المواصفة لنجعلها معيارًا عامًا. ويبدو أن Rails يتجه نحو اعتمادها افتراضيًا في وضع API. المستقبل يبدو مبشّرًا جدًا.

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

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

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

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

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

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد