हम ग्राफक्यूएल सेवा को लागू कर रहे हैं, जो कई बैकएंड माइक्रोसर्विसेज के सामने है।

उदाहरण के लिए, हमारे पास एक Product है और प्रत्येक उत्पाद में इतिहास के आदेशों की एक सूची है। हमारा बैकएंड सर्वर दो REST API प्रदान करता है, एक उत्पाद विवरण डेटा के लिए, दूसरा उत्पाद की इतिहास ऑर्डर सूची लौटाता है।

हमारे क्लाइंट ऐप में दो पृष्ठ हैं: एक उत्पाद विवरण पृष्ठ है, दूसरा उत्पाद की इतिहास आदेश सूची है।

इसलिए, उत्पाद विवरण पृष्ठ में, हम केवल उत्पाद का विवरण डेटा प्राप्त कर सकते हैं, जबकि ऑर्डर सूची पृष्ठ में, हमें केवल सूची डेटा की आवश्यकता होती है।

नीचे की तरह GraphQL स्कीमा:

type ProductOrder {
    createAt: Date!
    userName: String!
    count: Int
}
type Product {
    productId: ID
    name: String
    orders: [ProductOrder!]!
}
Query {
    product(productId: ID): Product
}

और समाधानकर्ता इस प्रकार हैं

const resolvers = {
    Query: {
        product(_, { productId}){
            // fetch detail data from backend API
            return await someService.getProductDetail(productId);
        }
    },
    Product: {
        orders(product){
            // fetch order list from another API
            return await someService.getProductOrders(product.productId);
        }
    }
};

लेकिन हम उपरोक्त कोड का उपयोग करके एक संभावित अति-अनुरोध पाते हैं।

जब हम ऑर्डर सूची पृष्ठ से ऑर्डर सूची डेटा का अनुरोध करते हैं, तो हमें पहले उत्पाद विवरण एपीआई का अनुरोध करना होगा, उसके बाद हम ऑर्डर सूची एपीआई का अनुरोध कर सकते हैं। लेकिन हमें केवल ऑर्डर सूची डेटा चाहिए, कोई उत्पाद डेटा नहीं। इस मामले में, हमें लगता है कि उत्पाद विवरण अनुरोध बेकार है, हम इस अनुरोध को कैसे समाप्त कर सकते हैं?

यह बेहतर हो सकता है यदि हम आदेश सूची डेटा को पुनः प्राप्त करने के लिए केवल एक अनुरोध भेज सकें।

0
Jess 18 सितंबर 2019, 11:51

1 उत्तर

सबसे बढ़िया उत्तर

ए) अपनी स्कीमा को अलग तरह से तैयार करें:

संस्करण 1: ProductOrder को उत्पाद पर एक फ़ील्ड न बनाएं

type Query {
  product(productId: ID): Product
  productOrders(productId: ID): [ProductOrder!]
}

type Product {
  productId: ID
  name: String
}

संस्करण 2: विवरण को उत्पाद में एक उपक्षेत्र बनाएं

type Product {
    productId: ID
    details: ProductDetails!
    orders: [ProductOrder!]!
}

type ProductDetails {
  name: String
}

रिज़ॉल्वर के साथ:

const resolvers = {
  Query: {
    product: (_, { productId }) => productId,
  },
  Product: {
    id: productId => productId,
    details: productId => someService.getProductDetail(productId),
    orders: productId => someService.getProductOrders(productId),
  },
};

बी) यदि कोई विवरण अनुरोध नहीं किया जाता है तो फ़ेच छोड़ें

क्वेरी किए गए सबफ़ील्ड का निरीक्षण करने के लिए आप रिज़ॉल्वर के चौथे तर्क का उपयोग कर सकते हैं। आदर्श रूप से आप उसके लिए एक पुस्तकालय का उपयोग करते हैं। मुझे याद है कि हम ऐसा कर रहे थे जब हमारा फ्रंटएंड केवल किसी ऑब्जेक्ट के id फ़ील्ड का अनुरोध करेगा। यदि ऐसा है तो हम केवल { id } के साथ हल कर सकते हैं।

import { fieldList } from 'graphql-fields-list';

const resolvers = {
  Query: {
    product(_, { productId }, ctx, resolveInfo) {
      const fields = fieldList(resolveInfo);
      if (fields.filter(f => f !== 'orders' || f !== 'id').length === 0) {
        return { productId };
      }
      return someService.getProductDetail(productId);
    },
  },
};

सी) सबफील्ड पूछे जाने तक देरी से प्राप्त करें

यदि आप पहले से ही Dataloader का उपयोग कर रहे हैं तो यह करना अपेक्षाकृत आसान है। क्वेरी रिज़ॉल्वर में तुरंत विवरण लाने के बजाय आप फिर से आईडी पास कर देते हैं और प्रत्येक विवरण फ़ील्ड को स्वयं विवरण प्राप्त करने देते हैं। यह प्रतिवाद लगता है लेकिन Dataloader यह सुनिश्चित करेगा कि आपकी सेवा केवल एक बार पूछताछ की जाए:

const resolvers = {
  Query: {
    product: (_, { productId }) => productId,
  },
  Product: {
    id: productId => productId,
    // same for all other details fields
    name: (productId, args, ctx) => ctx.ProductDetailsByIdLoader.load(productId)
      .then(product => product.name),
    orders: productId => someService.getProductOrders(productId),
  },
};

यदि आपके पास डेटालोडर नहीं है तो आप एक साधारण प्रॉक्सी बना सकते हैं:

class ProductProxy {
  constructor(id) {
    this.id = id;
    let cached = null;
    this.getDetails = () => {
      if (cached === null) {
        cached = someService.getProductDetails(productId)
      }
      return cached;
    }
  }
  // args not needed but for you to see how graphql-js works
  productId(args, ctx, resolveInfo) {
    return this.id;
  }
  name(args, ctx, resolveInfo) {
    return this.getDetails().then(details => details.name);
  }
  orders(args, ctx, resolveInfo) {
    return someService.getProductOrders(this.id);
  }
}

const resolvers = {
  Query: {
    product: (_, { productId }) => new ProductProxy(productId),
  },
  // No product resolvers need here
};
1
Herku 18 सितंबर 2019, 13:18