Window.pipedriveLeadboosterConfig = { القاعدة: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', الإصدار: 2, } ؛(الدالة () { var w = نافذة إذا كان (w.LeadBooster) { console.warn('LeadBooster موجود بالفعل') } وإلا { { w.LeadBooster = { q: [], على: دالة (ن، ح) { { هذا.q.push({ t: 'o'، n: n، n: n، h: h }) }, الزناد: الدالة (n) { هذا.q.push({ t: 't'، n: n: n }) }, } } })() تضمين الموارد الفرعية في واجهة برمجة تطبيقات REST-ish - The Codest
The Codest
  • نبذة عنا
  • الخدمات
    • تطوير البرمجيات
      • تطوير الواجهة الأمامية
      • تطوير الواجهة الخلفية
    • Staff Augmentation
      • مطورو الواجهة الأمامية
      • مطورو الواجهة الخلفية
      • مهندسو البيانات
      • مهندسو السحابة
      • مهندسو ضمان الجودة
      • أخرى
    • استشاري
      • التدقيق والاستشارات
  • الصناعات
    • التكنولوجيا المالية والمصرفية
    • E-commerce
    • أدتك
    • التكنولوجيا الصحية
    • التصنيع
    • الخدمات اللوجستية
    • السيارات
    • إنترنت الأشياء
  • القيمة مقابل
    • CEO
    • CTO
    • مدير التوصيل
  • فريقنا
  • دراسات الحالة
  • اعرف كيف
    • المدونة
    • اللقاءات
    • ندوات عبر الإنترنت
    • الموارد
الوظائف تواصل معنا
  • نبذة عنا
  • الخدمات
    • تطوير البرمجيات
      • تطوير الواجهة الأمامية
      • تطوير الواجهة الخلفية
    • Staff Augmentation
      • مطورو الواجهة الأمامية
      • مطورو الواجهة الخلفية
      • مهندسو البيانات
      • مهندسو السحابة
      • مهندسو ضمان الجودة
      • أخرى
    • استشاري
      • التدقيق والاستشارات
  • القيمة مقابل
    • CEO
    • CTO
    • مدير التوصيل
  • فريقنا
  • دراسات الحالة
  • اعرف كيف
    • المدونة
    • اللقاءات
    • ندوات عبر الإنترنت
    • الموارد
الوظائف تواصل معنا
السهم الخلفي العودة إلى الوراء
2022-03-22
تطوير البرمجيات

تضمين الموارد الفرعية في واجهة برمجة تطبيقات REST-ish API

The Codest

كرزيستوف بوزيفيتش

Software Engineer كبير Software Engineer

سنقوم ببناء تطبيق رف كتب لسرد الكتب مع (أو بدون) بيانات المؤلفين.

ما الذي سنفعله؟

سنقوم ببناء تطبيق رف كتب لسرد الكتب مع (أو بدون) بيانات المؤلفين. سيكون هناك #index وبعض البذور. سيكون هذا مثالاً على تطبيق لتوضيح كيف يمكنك منح المستخدم التحكم في الموارد الفرعية في واجهة برمجة تطبيقات REST-ish API.

"معايير القبول"

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

الأدوات

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

التطبيق

لننشئ مثالاً على التطبيق. لن نضيف إطار اختبار لأنه خارج نطاقنا.

قضبان رف كتب جديدة -T

أنشئ الآن المؤلف الطراز:

القضبان g اسم مؤلف النموذج: سلسلة
#=> استدعاء السجل النشط
#=> إنشاء db/migrate/2021122224084524_create_authors.rb
#=> إنشاء التطبيق/النماذج/المؤلفين.rb

و كتاب:

القضبان ز نموذج كتاب نموذج القضبان المؤلف: مراجع العنوان: سلسلة
# => استدعاء السجل النشط
# => إنشاء تطبيق db/migrate/202112224084614_create_books.rb
# => إنشاء التطبيق/النماذج/كتاب.rb

سنحتاج إلى بعض البذور:

# db/seeds.rb

dumas = المؤلف.create(الاسم: 'Alexandre Dumas')
lewis = Author.create(name: 'C.S. Lewis')
مارتين = المؤلف.create(الاسم: 'Robert C. Martin')

كتاب.create(المؤلف: دوماس، العنوان: 'الفرسان الثلاثة')
كتاب.create(المؤلف: لويس، العنوان: 'الأسد والساحرة وخزانة الملابس')
كتاب.create(المؤلف: مارتن، العنوان: "رمز نظيف")

والآن نحن جاهزون لتشغيل عمليات الترحيل وبذر قاعدة البيانات:

قضبان قاعدة بيانات القضبان: ترحيل & وقضبان قاعدة بيانات القضبان: البذور

دعنا نضيف لديه_كثير للكتب في المؤلف الطراز:

# التطبيق/النماذج/المؤلف.rb

صنف المؤلف <سجل التطبيق
  لديه_كثير :كتب
نهاية

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

# config/initializers/inflections.rb

ActiveSupport::Inflector.inflector.inflections(:en) do |inflect|
  inflect.acronym 'API'
النهاية

حسنًا، لنضف المتسلسل الخاص بنا إلى ملف الجوهرة:

# أضف إلى ملف الأحجار الكريمة

جوهرة 'blueprinter'

وبالطبع قم بتثبيته:

تثبيت الحزمة

ثم يمكننا بناء مخططاتنا:

# app/blueprints/author_blueprint.rb

صنف AuthorBlueprint < Blueprinter::Base
  المعرف :id

  الحقول :اسم
نهاية
# app/blueprints/book_blueprint.rb

صنف BookBlueprint < Blueprinter::Base
  المعرف :معرف

  الحقول :العنوان

  الارتباط :المؤلف، المخطط: مخطط المؤلف
النهاية

إضافة وحدة تحكم أساسية لـ واجهة برمجة التطبيقات:

# التطبيق/المتحكمون/API/v1/base_controller.rb

وحدة API
  الوحدة النمطية V1
    صنف BaseController < ActionController::API
    نهاية
  نهاية
النهاية

ومسودة نسخة مراقب الكتب:

# التطبيق/عناصر التحكم/API/v1/books_controller.rb

الوحدة النمطية API
  الوحدة النمطية V1
    صنف BooksController <المتحكم الأساسي
      تعريف الفهرس
        الكتب = جميع الكتب

        تصيير json: BookBlueprint.render(الكتب)
      النهاية
    النهاية
  النهاية
النهاية

يجب علينا أيضًا تحديد التوجيه بالطبع:

# config/routes.rb

Rails.application.routes.routes.draw do
  مساحة الاسم :api do
    مساحة الاسم :v1 do
      الموارد :كتب، فقط: :فهرس
    نهاية
  النهاية
النهاية

لنختبر ما قمنا به حتى الآن:

القضبان ق 
الضفيرة http://localhost:3000/api/v1/books

# => [{"id":1,"author":{"id":1,"id":1,"name":"Alexandre Dumas"},"title":"The Three Musketeers"},{"id":2,"author":{"id":2,"id":2,"name":"C.س. لويس"},"العنوان":"الأسد والساحرة وخزانة الملابس"},{"المعرف":3,"المؤلف":{"المعرف":3,"المؤلف":{"المعرف":3,"الاسم":"روبرت سي مارتن"},"العنوان":"نظيف الكود"}]

تبدو البيانات على ما يرام، ماذا عن السجلات؟

سجلات الطلبات # (n+1)

تم بدء GET "/API/v1/books" ل 127.0.0.1 في 2021-12-24 10:19:40 +0100
تتم المعالجة بواسطة API::V1::BooksController#index ك*/*
  تحميل الكتب (0.1 مللي ثانية) حدد "الكتب".* من "الكتب"
  ↳ ↳ التطبيق/المتحكمون/مراقبو/موقع API/v1/books_controller.rb:7:في 'الفهرس'
  تحميل المؤلفين (0.1 مللي ثانية) حدد تحديد "المؤلفين".* من "المؤلفين" حيث "المؤلفون"."id" = ؟ LIMIT ?  [[["المعرف"، 1]، ["LIMIT"، 1]]
  
  تحميل المؤلفين (0.1 مللي ثانية) حدد تحديد "المؤلفين".* من "المؤلفين" حيث "المؤلفون"."id" = ؟ LIMIT ?  [[["المعرف"، 2]، ["LIMIT"، 1]]
  
  تحميل المؤلفين (0.1 مللي ثانية) حدد تحديد "المؤلفين".* من "المؤلفين" حيث "المؤلفون"."id" = ؟ LIMIT ?  [[["المعرف"، 3]، ["LIMIT"، 1]]
  
تم إكمال 200 موافق في 6 مللي ثانية (المشاهدات: 0.1 مللي ثانية | ActiveRecord: 0.4 مللي ثانية | التخصيصات: 3134)

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

دعونا نعرّف ثابتًا يحتفظ بمعلومات حول ما يمكن للمستخدم تضمينه في كتب#index الإجراء:

# lib/constants/books/includes.rb

وحدة الثوابت
  وحدة الكتب
    وحدة التضمينات
      مسموح = {
        فهرس %i[
          مؤلف
        ].تجميد
      }.freeze
    النهاية
  النهاية
النهاية

بعد ذلك، نحدد مساحة اسم لثوابت الكائنات الفارغة:

# lib/constants/empty.rb

وحدة الثوابت
  وحدة فارغة
    HASH = {}.freeze
  النهاية
النهاية

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

# app/services/permit_includes.rb

تتطلب 'ثوابت/فارغة'
تتطلب 'ثوابت/ثوابت/كتب/مشتملات'

فئة PermitIncludes
  فارغة = الثوابت::فارغة

  كوما = '،'
  SLASH = '/'

  INCLUDES_FORMAT = / A[a-z]+(,[a-z]+)*z/.freeze
  المسموح_بإدراجها = {
    الكتب الثوابت::كتب::يشمل::ALLOWED
  }.freeze

  def call(params, resources: default_resources_key(params), purpose: default_purpose(params))
    إرجاع فارغ::HASH ما لم يتضمن_مرسل؟ (بارامز)
    إرجاع فارغ::HASH ما لم يتضمن_صحيح؟(params)

    التضمينات_المطلوبة = تحليل_التضمينات(params)
    المسموح_بالتضمينات المسموح بها = تصفية_التضمينات(تضمينات_مطلوبة، الموارد، الغرض)

    المسموح_بإدراجها.index_with(صحيح)
  النهاية

  خاص

  def default_resources_key(params)
    رفع (ArgumentError, 'params :مفتاح وحدة التحكم يجب أن يكون سلسلة') إلا إذا كان params[:وحدة تحكم].is_a?(String)

    params[:وحدة تحكم].split(SLASH).last&.to_sym
  النهاية

  def default_purpose(params)
    رفع(ArgumentError, 'البارامز :مفتاح الإجراء يجب أن يكون سلسلة') إلا إذا كان البارامز[:إجراء].is_a?(سلسلة)

    params[:إجراء].to_sym
  إنهاء

  ديف يتضمن_الإرسال؟(params)
    params.key?(:includes)
  نهاية

  ديف includes_valid?(params)
    إرجاع خطأ ما لم يكن params[:يتضمن].is_a?(String)

    params[:includes].match؟(INCLUDES_FORMAT)
  النهاية

  تعريف parse_includes(params)
    params[:includes].split(COMMA).map(&:to_sym)
  النهاية

  def filter_includes(requested_includes, resources_key, purpose)
    المطلوب_يتضمن & ALLOWED_INCLUDES [الموارد_المفتاح] [الغرض]
  نهاية
النهاية

نحتاج الآن إلى استخدام المفاتيح لتحميل التضمينات وتمرير تجزئة التضمينات نفسها إلى أداة التسلسل:

# التطبيق/عناصر التحكم/API/v1/books_controller.rb

الوحدة النمطية API
  الوحدة النمطية V1
    صنف BooksController <المتحكم الأساسي
      تعريف الفهرس
        يتضمّن = PermitIncludes.new.call(params)
        الكتب = Book.includes.includes(includes.keys).all

        تصيير json: تصيير BookBlueprint.render(كتب، يتضمن: يتضمن)
      النهاية
    النهاية
  النهاية
النهاية

وهذه هي الطريقة التي يجب أن نعدّل بها أداة التسلسل لدينا - نقوم بتحميل الارتباط فقط إذا كان متضمنًا:

# app/blueprints/book_blueprint.rb
صنف BookBlueprint (_حقل_الاسم، _كتاب، خيارات) {
                         خيارات[:يتضمن] && خيارات[:يتضمن][:المؤلف]
                       }
النهاية

لنختبرها مرة أخرى:

القضبان ق
تجعيد http://localhost:3000/api/v1/books
# => [{"المعرف":1، العنوان: "الفرسان الثلاثة"},{"المعرف":2، العنوان: "الأسد والساحرة وخزانة الملابس"},{"المعرف":3، العنوان: "الرمز النظيف"}]
سجلات طلب # (نقوم بتحميل الكتب فقط)
بدأ GET "/API/v1/books" لـ ::1 في 2021-12-24 10:33:41 +0100
تتم المعالجة بواسطة API::V1::V1::BooksController#index ك*/*
   (0.1 مللي ثانية) حدد sqlite_version (*)
  ↳ التطبيق/المتحكمون/API/v1/books_controller.rb:8:في 'الفهرس'
  تحميل الكتب (0.1 مللي ثانية) حدد "الكتب".* من "الكتب"
  ↳ التطبيق/المتحكمون/واجهة المستخدم/واجهة المستخدم/v1/books_controller.rb:8:8:في 'الفهرس'
تم الإكمال 200 موافق في 9 مللي ثانية (المشاهدات: 0.1 مللي ثانية | ActiveRecord: 0.9 مللي ثانية | التخصيصات: 4548)

جيد، لم نجتاز التضمينات، لذا حصلنا على الكتب فقط، دون المؤلفين. لنطلبهم الآن:

تجعيد 'http://localhost:3000/api/v1/books?includes=author'
# => [{"id":1,"author":{"id":1,"name":"Alexandre Dumas"},"title":"The Three Musketeers"},{"id":2,"author":{"id":2,"id":2,"name":"C.S. لويس"},"العنوان":"الأسد والساحرة وخزانة الملابس"},{"المعرف":3,"المؤلف":{"المعرف":3,"المؤلف":{"المعرف":3,"الاسم":"روبرت سي مارتن"},"العنوان":"الرمز النظيف"}]% 
سجلات الطلبات # (تم التخلص من n+1)

تم بدء GET "/API/v1/books?includes=author" لـ ::1 في 2021-12-24 10:38:23 +0100
تتم المعالجة بواسطة API::V1::BooksController#index كـ */*
  المعلمات: {"includes"=>"author"}
  تحميل الكتب (0.1 مللي ثانية) حدد "الكتب".* من "الكتب"
  
  تحميل المؤلفين (0.2 مللي ثانية) حدد "المؤلفين".* من "المؤلفين" حيث "المؤلفون"."id" في (?, ?, ?, ?) [[["id", 1]، ["id", 2]، ["id", 3]]
  
تم الإكمال 200 موافق في 17 مللي ثانية (المشاهدات: 0.1 مللي ثانية | ActiveRecord: 0.7 مللي ثانية | التخصيصات: 7373)

رائع! لقد قمنا بتحميل الجمعية وإزالتها n+1 مشكلة. يمكن استخدام الخدمة لأي مورد، كل ما نريده هو إضافة الثوابت المسموح بها بالصيغة المناسبة وإضافتها إلى تصاريح التضمينات::ALLOWED_INCLUDES.

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

مقالات ذات صلة

التكنولوجيا المالية

5 أمثلة على أفضل استخدامات روبي

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

The Codest
بافيل موسزينسكي Software Engineer
تطوير البرمجيات

تعدد الأشكال في روبي و GraphQL

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

لوكاش برزشيتش
E-commerce

معضلات الأمن السيبراني: تسريبات البيانات

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

The Codest
ياكوب جاكوب جاكوبوفيتش CTO وشريك مؤسس CTO
تطوير البرمجيات

تطبيق بسيط من روبي بسيط من الصفر مع السجل النشط

MVC هو نمط تصميم يقسم مسؤوليات التطبيق لتسهيل التنقل فيه. يتبع Rails هذا النمط التصميمي حسب الاصطلاح.

The Codest
داميان واتروبا Software Engineer

اشترك في قاعدة معارفنا وابقَ على اطلاع على آخر المستجدات في قطاع تكنولوجيا المعلومات.

    نبذة عنا

    The Codest - شركة دولية لتطوير البرمجيات لها مراكز تقنية في بولندا.

    المملكة المتحدة - المقر الرئيسي

    • المكتب 303 ب، 182-184 شارع هاي ستريت نورث E6 2JA
      لندن، إنجلترا

    بولندا - مراكز التكنولوجيا المحلية

    • مجمع مكاتب فابريتشنا المكتبي، أليجا
      بوكوجو 18، 31-564 كراكوف
    • سفارة الأدمغة، كونستروكتورسكا
      11, 02-673 02-673 وارسو، بولندا

      The Codest

    • الصفحة الرئيسية
    • نبذة عنا
    • الخدمات
    • دراسات الحالة
    • اعرف كيف
    • الوظائف
    • القاموس

      الخدمات

    • استشاري
    • تطوير البرمجيات
    • تطوير الواجهة الخلفية
    • تطوير الواجهة الأمامية
    • Staff Augmentation
    • مطورو الواجهة الخلفية
    • مهندسو السحابة
    • مهندسو البيانات
    • أخرى
    • مهندسو ضمان الجودة

      الموارد

    • حقائق وأساطير حول التعاون مع شريك خارجي لتطوير البرمجيات
    • من الولايات المتحدة الأمريكية إلى أوروبا: لماذا تقرر الشركات الأمريكية الناشئة الانتقال إلى أوروبا؟
    • مقارنة مراكز تطوير التكنولوجيا في الخارج: تك أوفشور أوروبا (بولندا)، آسيان (الفلبين)، أوراسيا (تركيا)
    • ما هي أهم التحديات التي تواجه CTOs ومديري تكنولوجيا المعلومات؟
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • شروط استخدام الموقع الإلكتروني

    جميع الحقوق محفوظة © 2025 بواسطة The Codest. جميع الحقوق محفوظة.

    arArabic
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek arArabic