Apollo-link-rest: مناقشة الميزة: إضافة الاستدلال التلقائي للنوع

تم إنشاؤها على ٢٦ يناير ٢٠١٨  ·  22تعليقات  ·  مصدر: apollographql/apollo-link-rest

أهلا،

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

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

في حالة الاستخدام الخاصة بي ، سيسمح ذلك بتوصيل عميل GraphQL بسرعة بخادم REST ، مع توفير أسماء __typenames المخصصة الضرورية فقط باستخدام تطبيقfbartho .

لقد قمت بتنفيذ هذه الميزة وسأفتح العلاقات العامة قريبًا.

enhancement💡 question❔

التعليق الأكثر فائدة

mpgon & @ Rsullivan00 سأدعم إضافة قسم #### Related Libraries مع رابط ووصف 1-line للمكتبات الخاصة بك إلى README.

ال 22 كومينتر

شكرا للمساهمة @ sky-franciscogoncalves !! أعتقد أن هذا مهم للمناقشة.

كان قلقي الشخصي هو أنه في واجهات برمجة التطبيقات الخاصة بـ GraphQL التي رأيتها ، كان لأبسط query اسم حقل مطابق يمكن حفظه بأمان في pascal في __typename . كان لدى العديد منهم اقتران بديل ، في حين أن جميع mutation s تقريبًا لن يعمل.

بشكل عام ، عند تنفيذ typePatcher أعتقد أن الناس كانوا قلقين بشأن وجود سحر "خطير" قد لا تريده - وبعد ذلك سيحتاجون إلى التعطيل المشروط. => التعقيد!

ما زلت مبتدئًا في GraphQL ، لذلك سأحب ذلك إذا كان peggyrayzis أو jbaxleyiii أو

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

type Action {
  kind: ActionKind!
  name: String!
}

ملاحظة لكي يعمل غلاف باسكال ولا يتعارض مع الأنواع الأخرى المحتملة التي سأحتاج إلى الاتصال بها -> نوع الإجراء الذي يبدو غريبًا كما تعلم بالفعل أنك داخل حدث

type Action {
  actionKind: ActionKind!
  name: String!
}

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

type Schedule {
  start: Float
  end: Float
}
type Task {
  schedule: Schedule!
  name: String!
}
type Job {
  schedule: Schedule!
  name: String!
}

ما رأيك في زيادة التحميل على التعليق التوضيحي الحالي بحيث يمكن استخدامه للحقول المتداخلة بدون سمة المسار؟

query MyQuery {
  action @rest(type: "Action", path: "action/") {
    id
    name
    kind @rest(type: "ActionKind") {
      name
    }
  }
}

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

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

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

ومع ذلك ، قد يكون التوجيه @type(…) مضافًا في الغالب ، لذلك لن أعارض بشدة تنفيذ هذه الإستراتيجية. - سنتان.

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

كحل شخصي ، أنا أعمل مع المخططات من أجل الإعداد الخاص بي apollo-link-state / apollo-link-rest في شركتي ، وكتبت أداة تراقب / تحلل هذه الملفات ، وتقوم بإنشاء رمز typePatcher code - يستدعي أيضًا apollo-codegen لإنشاء روابط TypeScript. سأشاركه هنا ، لكنه ليس نصًا ودودًا حقًا ، لذا لا أعتقد أنه حل قابل للتطبيق بشكل عام ، لكنه سيعمل على تلبية احتياجات فريقي.

شكرا لملاحظاتك. ما زلت جديدًا جدًا على GraphQL ، لذلك أنا آسف لقلة معرفتي.

في رأيي ، يمكن أن يكون الحل الحالي مربكًا للقادمين الجدد. نظرًا لأنه ليس من الواضح تمامًا كيف يعمل TypePatcher ، ولا كيف يجب على المستخدم استخدامه.

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

من ناحية أخرى ، هل يجب أن نفعل الشيء نفسه إذا التزمنا بالحل الحالي؟

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

إذا كان لدينا مخطط مثل هذا:

type Schedule {
  start: Float
  end: Float
}
type Task {
  schedule: Schedule!
  name: String!
}

ثم عند إجراء الاستعلام ، يمكننا التحقق من أن النوع Task تم تعريفه بالفعل في المخطط وأن الكائن المتداخل schedule سيكون له اسم النوع المستنتج من النوع المحدد في المخطط.

query MyQuery {
  task @rest(type: "Task", path: "task/") {
    name
    schedule {
      start
      end
    }
  }
}

هل يمكن لشيء مثل هذا العمل؟

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

query MyQuery {
  action @rest(type: "Action", path: "action/") {
    id
    name
    kind @type(name: "ActionKind") {
      name
    }
  }
}

إنه أكثر وضوحًا للقادمين الجدد.

قد يكون تحديد الأنواع التي تقترحها مربكًا أيضًا لشخص يتعلم GraphQL لأن هذا شيء عليك القيام به من جانب الخادم.

أحب هذه المحادثة

sabativi ، شكرا

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

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

مثال حيث قد تتغير مجموعة السمات بناءً على خاصية النوع:

{
  animals: [
    {
      type: 'cat',
      attributes: {
          ....
      },
    },
    {
      type: 'dog',
      attributes: {
          ....
      },
    },
  ],
}

مشكلة تضمين كل شيء في استعلامك هي أنك يجب أن تكرر نفسك في كل مكان.

مثال: على الرغم من إمكانية تضمين كائن مستخدم في N APIs ، يجب عليك إرفاق التعليقات التوضيحية للنوع لكل جزء فرعي من المستخدم في كل استعلام له مستخدم. إذا كان لديك currentUser ، buddylist ، recommendedList ، nearUsers مثل استعلامات وكان المستخدم لديه عناوين ، linkedAccounts ، appData ، كنماذج فرعية ، فعليك كتابة 4 x 3 = 12 اكتب التعليقات التوضيحية - وهذا بافتراض أن كل استعلام يتم عرضه مرة واحدة فقط! باستخدام typePatcher المطبق حاليًا ، ما عليك سوى التصحيح مرة واحدة لكل نموذج فرعي.

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

لكي أكون واضحًا ، لا أمانع إذا أضفنا التعليق التوضيحي - سيكون هذا رائعًا لحقن REST api خفيفة الوزن جدًا. - إذا كنت تريد فقط التفاف نقطة أو نقطتين صغيرتين من نقاط نهاية REST. سأصاب بخيبة أمل إذا كانت هذه هي الطريقة الوحيدة أو الموصى بها لالتفاف واجهات برمجة التطبيقات. نظرًا لأننا نوصي باستخدام link-rest كخطوة أولى للأشخاص الذين يقومون بترحيل واجهات برمجة التطبيقات كاملة الحجم إلى GraphQL ، فإن تشجيع هذا النمط قد يخيف عددًا غير قليل من الأشخاص تمامًا!

اتفق معك تماما. يجب أن نحافظ على كلا النهجين ، وإذا كان ذلك ممكنًا ، فلندعهما يتفاعلان.

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

في الوقت الحالي ، يمكنه إضافة اسم نوع لكل كائن متداخل ومصفوفة (من المصفوفات) من العناصر التي تضيف التعليق التوضيحي @type(name: "Type") .

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

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

يمكنك التحقق من ذلك هنا . لقد أضفت حالات اختبار توضح ما ذكرته سابقًا.

fbartho يمكن حل وجود استعلامات متعددة باستخدام نفس النوع باستخدام الأجزاء. يمكنك فقط تحديد جزء واحد يضيف جميع التعليقات التوضيحية @type(name: "Type") ويمكن للمستخدمين فقط سحب الأجزاء.

@ pyros2097 يعد استخدام الأجزاء المشتركة لتحسين الاستعلامات باستخدام @type فكرة ذكية لم أفكر فيها.

  • كيف ستشرع بالضبط في مشاركة هذا الجزء بحيث يمكن لجميع الاستعلامات استخدامه؟
  • ماذا يحدث عندما يتعارض توجيهان؟

هذه هي الطريقة التي كنت أنوي القيام بها باستخدام apollo-link-rest. لكنها تفشل هي أنواع متداخلة بعمق. على سبيل المثال: يطرح خطأ للصورة {url} يقول لا يمكن قراءة __typename لـ 'url' التي سيحلها التوجيه

export const UserFragment = gql`
  fragment UserFragment on User {
    id
    first_name
    last_name
    image @type(name: "Image") {
      ...ImageFragment
    }
  }
`;

export const ImageFragment = gql`
  fragment ImageFragment on Image {
    url
    width
    height
  }
`;

export const AdventureFragment = gql`
  fragment AdventureFragment on Adventure {
    id
    name
    user @type(name: "User") {
      ...UserFragment
    }
    cover_photo @type(name: "Image") {
      ...ImageFragment
    }
    created_at
    updated_at
  }
`;

export const GetUserQuery = gql`
  query UserAdventures($page: Int!) {
    user @rest(method: "GET", path: "/api/current", type: "User") {
      id @export(as: "id")
      ...UserFragment
      adventures(page: $page) @rest(method: "GET",  path: "/api/adventures", params: { id: $id }, type: "Adventure") {
        ...AdventureFragment
      }
    }
  }
  ${ImageFragment}
  ${UserFragment}
  ${AdventureFragment}
`;
  • من السهل مشاركة الجزء الذي تحتاج فقط إلى إعلانه بشكل منفصل وحقنه في الاستعلام الذي ترغب في استخدامه فيه.
  • إذا اصطدم توجيهان ، فأنا أعتقد أن التوجيه / الجزء الأخير مع هذا التوجيه سيكون له الأسبقية. سوف تحتاج للتحقق من هذا.

@ pyros2097 - ما هي بيانات JSON التي ___typename من url إذا كان url مجرد سلسلة؟

عنوان url هو مجرد سلسلة ولكنه يعطيني تحذيرًا لجميع المفاتيح في جزء الصورة. كما أنه يخبرني باستخدام IntrospectionFragmentMatcher من ذاكرة التخزين المؤقت apollo-inmemory-cache. يمكن أن يكون هذا ذاكرة تخزين مؤقت أبولو في الذاكرة لا يمكنها تحديد أنواع التخزين المؤقت ولا تتعلق بـ apollo-link-rest.

fragmentMatcher: By default, the InMemoryCache uses a heuristic fragment matcher.
If you are using
fragments on unions and interfaces, you will need to use an IntrospectionFragmentMatcher.
For more
information, please read [our guide to setting up fragment matching for unions & interfaces].

@ sky-franciscogoncalves لا تتردد في إرسال التعليق التوضيحي @type() الخاص بك كعلاقات عامة إلى هذا الريبو حتى نتمكن من مناقشته مباشرة دون مزيد من التشابك في هذه المناقشة حول استدلال اسم النوع "التلقائي".

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

مرحباfbartho! أعلم أن هذا الموضوع مغلق لبعض الوقت ، لكن قيل سابقًا ، ليس هناك بعد ، بقدر ما أجد ، طريقة لاستنتاج أسماء الأنواع بسهولة. على الرغم من أن التعليق التوضيحي @type جميل جدًا لإجراء التجارب ، إلا أنه لا يتم توسيعه. وعلى الرغم من أن أداة الطباعة الوظيفية التي تم تطويرها في رقم 55 هي بديل لطيف للغاية ، إلا أنني وجدت أنها لا تزال مطولة جدًا لكتابة واجهة برمجة تطبيقات كبيرة.
بهذه الطريقة ، سأكون مهتمًا جدًا بالآراء حول lib الذي صنعته لكتابة تصحيح API كبيرة بسهولة. يطلق عليه apollo-type-patcher وإليك عرض codeandbox

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

mpgon & @ Rsullivan00 سأدعم إضافة قسم #### Related Libraries مع رابط ووصف 1-line للمكتبات الخاصة بك إلى README.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات