क्या दोनों के बीच कोई उल्लेखनीय अंतर है? मुझे रनटाइम और स्टार्टअप प्रदर्शन से लेकर सुविधाओं और वर्कफ़्लो अंतर तक किसी भी चीज़ में दिलचस्पी है। दस्तावेज़ीकरण अंतर को समझाने पर खराब काम करता है और जब मुझे एक का दूसरे पर उपयोग करना चाहिए।

दोनों संस्करणों में उदाहरण:

बिल्डस्कीमा

const { graphql, buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

const root = { hello: () => 'Hello world!' };

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

ग्राफक्यूएलस्कीमा

const { graphql, GraphQLSchema, GraphQLObjectType, GraphQLString } = require('graphql');

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      hello: {
        type: GraphQLString,
        resolve: () => 'Hello world!'
      }
    })
  })
});

graphql(schema, '{ hello }').then((response) => {
  console.log(response);
});
38
Solo 31 पद 2018, 09:00

1 उत्तर

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

buildSchema फ़ंक्शन SDL (स्कीमा परिभाषा भाषा) में एक स्कीमा लेता है और एक GraphQLSchema ऑब्जेक्ट देता है। प्रत्येक विधि से उत्पन्न दो समान स्कीमा को देखते हुए, रनटाइम प्रदर्शन समान होगा। buildSchema का उपयोग करने वाले सर्वर के लिए स्टार्टअप समय धीमा होगा क्योंकि एसडीएल को पार्स करने से एक अतिरिक्त चरण जुड़ जाता है जो अन्यथा मौजूद नहीं होगा - क्या कोई ध्यान देने योग्य अंतर होगा, मैं निश्चित रूप से नहीं कह सकता .

buildSchema का उपयोग करना आमतौर पर अनुचित है, क्योंकि यह आपके स्कीमा की कार्यक्षमता को गंभीर रूप से सीमित कर देता है।

buildSchema का उपयोग करके जेनरेट किया गया एक स्कीमा:

  • अलग-अलग क्षेत्रों के लिए समाधान कार्यों को निर्दिष्ट नहीं कर सकता
  • प्रकारों के लिए या तो resolveType या isTypeOf गुण निर्दिष्ट नहीं कर सकते, जिससे Unions और Interfaces का उपयोग करना असंभव हो जाता है
  • कस्टम स्केलर का उपयोग नहीं कर सकते

आइटम #1 पर पर्याप्त जोर नहीं दिया जा सकता -- buildSchema आपको अपने स्कीमा में किसी भी फ़ील्ड के लिए रिज़ॉल्वर फ़ंक्शन निर्दिष्ट करने की अनुमति नहीं देता है। इसमें आपके Query और Mutation प्रकार के फ़ील्ड शामिल हैं। उदाहरण जो buildSchema का उपयोग करते हैं, ग्राफ़क्यूएल के डिफ़ॉल्ट रिज़ॉल्वर व्यवहार पर भरोसा करके और root मान में पास करके इस समस्या को हल करते हैं।

डिफ़ॉल्ट रूप से, यदि किसी फ़ील्ड में कोई resolve फ़ंक्शन निर्दिष्ट नहीं है, तो GraphQL मूल मान (पैरेंट फ़ील्ड के रिज़ॉल्वर द्वारा लौटाया गया) की जांच करेगा और (यह मानते हुए कि यह एक ऑब्जेक्ट है) उस मूल मान पर एक संपत्ति खोजने का प्रयास करेगा जो क्षेत्र के नाम से मेल खाता है। यदि उसे कोई मेल मिलता है, तो वह उस मान के लिए फ़ील्ड को हल करता है। यदि मैच एक फ़ंक्शन होता है, तो यह पहले उस फ़ंक्शन को कॉल करता है और फिर फ़ंक्शन द्वारा दिए गए मान को हल करता है।

ऊपर के उदाहरण में, पहले स्कीमा में hello फ़ील्ड में रिज़ॉल्वर नहीं है। GraphQL मूल मान को देखता है, जो रूट स्तर फ़ील्ड के लिए रूट मान है जो पास किया जाता है। रूट मान में hello नामक फ़ील्ड होता है, और यह एक फ़ंक्शन, इसलिए यह फ़ंक्शन को कॉल करता है और फिर फ़ंक्शन द्वारा दिए गए मान को हल करता है। आप केवल hello गुण को एक फ़ंक्शन के बजाय एक स्ट्रिंग बनाकर समान प्रभाव प्राप्त कर सकते हैं।

उपरोक्त को देखते हुए, प्रश्न में दिए गए दो उदाहरण वास्तव में समान नहीं हैं। इसके बजाय, हमें इसके समकक्ष होने के लिए दूसरी स्कीमा को इस तरह संशोधित करना होगा:

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      hello: {
        type: GraphQLString,
      }
    })
  })
});

const root = { hello: () => 'Hello world!' };

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

रूट के माध्यम से एक रिज़ॉल्वर में गुजरना एक साफ चाल है, फिर से यह केवल रूट स्तर के क्षेत्रों (जैसे Query, Mutation या Subscription प्रकार के फ़ील्ड) के लिए काम करता है। यदि आप किसी भिन्न प्रकार के फ़ील्ड के लिए रिज़ॉल्वर प्रदान करना चाहते हैं, तो buildSchema का उपयोग करके ऐसा करने का कोई तरीका नहीं है।

निचली पंक्ति: buildSchema का उपयोग न करें।

लेकिन मैं SDL का उपयोग करना चाहता था!

और आप अभी भी कर सकते हैं! लेकिन... वेनिला GraphQL.js का उपयोग करके ऐसा न करें। इसके बजाय, यदि आप अपनी स्कीमा उत्पन्न करने के लिए एसडीएल का उपयोग करना चाहते हैं, तो आपको इसके बजाय graphql-tools' makeExecutableSchema का उपयोग करना चाहिए या apollo-server जैसे अधिक संपूर्ण समाधान का उपयोग करना चाहिए, जो makeExecutableSchema का उपयोग करता है ढकना। makeExecutableSchema आपको एक अलग resolvers ऑब्जेक्ट प्रदान करते हुए SDL का उपयोग करके एक स्कीमा को परिभाषित करने की अनुमति देता है। तो आप कर सकते हैं:

const typeDefs = `
  type Query {
    hello: String
  }
`

const resolvers = {
  Query: {
    hello: () => 'Hello!',
  },
}

const schema = makeExecutableSchema({ typeDefs, resolvers })

अंतर यह है कि, buildSchema के विपरीत, आप अन्य प्रकारों के लिए रिज़ॉल्वर भी प्रदान कर सकते हैं, और यहां तक ​​कि अपने इंटरफेस या यूनियनों के लिए resolveType गुण भी प्रदान कर सकते हैं।

const resolvers = {
  Query: {
    animals: () => getAnimalsFromDB(),
  }
  Animal: {
    __resolveType: (obj) => obj.constructor.name
  },
  Cat: {
    owner: (cat) => getOwnerFromDB(cat.ownerId),
  }
}

makeExecutableSchema का उपयोग करके, आप कस्टम स्केलर और स्कीमा निर्देशों को भी लागू कर सकते हैं, विभिन्न प्रकार के स्कीमा सत्यापन नियमों को आसानी से अनुकूलित कर सकते हैं और यहां तक ​​कि कार्यान्वयन प्रकारों को उनके इंटरफेस से रिज़ॉल्वर को इनहेरिट करने की अनुमति भी दे सकते हैं। जबकि GraphQL.js की मूल बातें समझना और GraphQLSchema कंस्ट्रक्टर का उपयोग करके एक बुनियादी स्कीमा कैसे उत्पन्न करना महत्वपूर्ण है, makeExecutableSchema एक अधिक पूर्ण और लचीला समाधान है जो कि अधिकांश परियोजनाओं के लिए जाना-पहचाना विकल्प होना चाहिए। . अधिक विवरण के लिए दस्तावेज़ देखें

अपडेट करें

यदि आप buildSchema का उपयोग करने पर तुले हुए हैं, तो वास्तव में ES6 कक्षाओं का उपयोग करके गैर-रूट प्रकारों के लिए रिज़ॉल्वर प्रदान करने में असमर्थता को प्राप्त करना संभव है। यह नमूना स्कीमा देखें। यह buildSchema की अन्य सभी सीमाओं को संबोधित नहीं करता है, लेकिन यह इसे और अधिक स्वादिष्ट बनाता है।

75
Daniel Rearden 17 जून 2019, 21:05