मुख्य सामग्री पर जाएं

GraphQL Codegen: GraphQL स्कीमा से टाइप-सुरक्षित कोड कैसे जनरेट करें

GraphQL Code Generator के लिए एक हैंड्स-ऑन गाइड जिसमें सेटअप और कॉन्फ़िगरेशन, जनरेटेड TypeScript टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स, Apollo, urql, और graphql-request के साथ इंटीग्रेशन, और वॉच मोड व CI के साथ ऑटोमेशन शामिल है।
अपडेट किया गया 2 अक्टू॰ 2026  · 12 मि॰ पढ़ें

AI के साथ खोजें

ChatGPTClaudePerplexity

GraphQL API के लिए हाथ से लिखे गए TypeScript टाइप्स उसी पल पुराने हो जाते हैं जब कोई स्कीमा बदलता है।

मान लें कि एक बैकएंड डेवलपर Course टाइप में title फ़ील्ड का नाम बदलकर name कर देता है। फ्रंटएंड फिर भी कंपाइल हो जाता है, क्योंकि हाथ से लिखे गए Course इंटरफ़ेस को बदलाव का पता ही नहीं है, इसलिए बग केवल रनटाइम पर दिखता है। असल दुनिया के ऐप्स में दर्जनों क्वेरी, म्यूटेशन और फ़्रैगमेंट होते हैं, तो आप समझ सकते हैं कि यह समस्या कितनी जल्दी बढ़ सकती है।

GraphQL Code Generator, या संक्षेप में GraphQL Codegen, आपके स्कीमा और GraphQL ऑपरेशंस को पढ़ता है और उन्हें टाइप्स, क्वेरी हेल्पर्स, क्लायंट इंटीग्रेशंस और दूसरे बोइलरप्लेट में बदल देता है, जिन्हें वरना आपको हाथ से लिखना पड़ता। यह प्रायः TypeScript और Apollo, urql जैसे लोकप्रिय क्लायंट्स के साथ उपयोग होता है। एक कमांड हर बार स्कीमा बदलने पर आपके टाइप्स को फिर से सिंक कर देता है।

इस लेख में, मैं एक छोटे TypeScript प्रोजेक्ट में GraphQL Codegen सेटअप करने, कॉन्फ़िगर करने, जनरेटेड टाइप्स का उपयोग करने और अपने वर्कफ़्लो के हिस्से के रूप में इसे ऑटोमैटिक रूप से चलाने की प्रक्रिया बताऊंगा।

GraphQL, REST की तुलना में कैसा है? अंतर और फायदे जानने के लिए हमारा Graph QL बनाम REST: एक संपूर्ण गाइड पढ़ें।

GraphQL Codegen क्या है?

GraphQL Codegen एक कमांड-लाइन टूल है जो GraphQL डिफ़िनिशंस को एप्लिकेशन कोड में बदलता है।

यह The Guild का एक ओपन-सोर्स प्रोजेक्ट है, और आप इसे अपने प्रोजेक्ट में डेवलपमेंट डिपेंडेंसी के रूप में इंस्टॉल करते हैं। यह तीन चीज़ों को जोड़ता है:

  • GraphQL स्कीमा: सर्वर और उसके क्लायंट्स के बीच का कॉन्ट्रैक्ट, जिसमें API के हर टाइप, फ़ील्ड और आर्ग्युमेंट की परिभाषा होती है
  • GraphQL ऑपरेशंस: क्वेरी, म्यूटेशन, सब्सक्रिप्शन और फ़्रैगमेंट जिन्हें आपका एप्लिकेशन API को भेजता है
  • जनरेटेड कोड: वे टाइप्स और हेल्पर्स जिन्हें Codegen स्कीमा और आपके ऑपरेशंस के आधार पर लिखता है

स्कीमा Codegen को बताता है कि क्या संभव है और ऑपरेशंस बताते हैं कि आपका एप्लिकेशन क्या मांगता है।

Codegen दोनों को मिलाता है, ताकि हर जनरेटेड टाइप किसी एक ऑपरेशन के रिस्पॉन्स के सटीक आकार से मेल खाए। यह हर ऑपरेशन को स्कीमा के विरुद्ध भी जाँचता है। परिचय में बदला गया title फ़ील्ड जनरेशन को एक त्रुटि जैसे Cannot query field "title" on type "Course" के साथ रोक देगा, और आप कोड चलने से पहले ही समस्या पकड़ लेंगे।

आउटपुट आपके प्लगइन्स और कॉन्फ़िगरेशन पर निर्भर करता है। Codegen स्वयं TypeScript नहीं लिखता; प्लगइन्स लिखते हैं। उदाहरण के लिए, typescript प्लगइन स्कीमा टाइप्स बनाता है, और typescript-operations प्लगइन आपकी क्वेरी और म्यूटेशन के लिए टाइप्स बनाता है। अन्य भाषाओं, जैसे Java और C#, के लिए भी प्लगइन्स हैं, लेकिन यह लेख TypeScript तक सीमित है।

ध्यान रहे कि Codegen आपका GraphQL सर्वर प्रतिस्थापित नहीं करता।

यह क्वेरीज़ को रिज़ॉल्व नहीं करता और न ही डेटा फ़ेच करता है। यह विकास के दौरान GraphQL डिफ़िनिशंस पढ़ता है और फ़ाइलें लिखता है। बाकी काम आपका सर्वर और आपका GraphQL क्लायंट करते हैं।

GraphQL Codegen कैसे काम करता है

हर Codegen सेटअप एक ही प्रवाह का अनुसरण करता है: स्कीमा + GraphQL ऑपरेशंस -> Codegen कॉन्फ़िगरेशन -> जनरेटेड कोड।

GraphQL Codegen वर्कफ़्लो का डायग्राम

GraphQL Codegen वर्कफ़्लो का डायग्राम

सामान्य विचार यह है:

  1. स्कीमा प्रदान करें: Codegen को लोकल .graphql फ़ाइल या चल रहे GraphQL एंडपॉइंट की ओर इंगित करें, जिसे Codegen introspection के माध्यम से पढ़ता है

  2. Codegen को अपने ऑपरेशंस की ओर इंगित करें: src/**/*.ts जैसी ग्लोब पैटर्न का उपयोग करें ताकि Codegen आपकी क्वेरी, म्यूटेशन और फ़्रैगमेंट ढूंढ सके

  3. प्लगइन्स और आउटपुट टार्गेट्स कॉन्फ़िगर करें: Codegen को बताएं कि कौन-सी फ़ाइलें लिखनी हैं और किस प्लगइन से कौन-सी फ़ाइल जनरेट होगी

  4. Codegen चलाएं: npx graphql-codegen चलाएं ताकि स्कीमा लोड हो, आपके ऑपरेशंस वैलिडेट हों और आउटपुट लिखा जाए

  5. जनरेटेड आर्टिफैक्ट्स का उपयोग करें: अपने एप्लिकेशन कोड में जनरेटेड टाइप्स और डॉक्यूमेंट नोड्स इम्पोर्ट करें

कदम 1 से 3 एक ही कॉन्फ़िग फ़ाइल में रखे जाते हैं, आमतौर पर codegen.ts। एक कोर्स कैटलॉग प्रोजेक्ट के लिए इसका सबसे छोटा संस्करण यहां है:

import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  // Step 1: Where the schema comes from
  schema: "schema.graphql",
  // Step 2: Where your operations are placed
  documents: ["src/**/*.ts"],
  // Step 3: What to generate and where to write it
  generates: {
    "./src/gql/": { preset: "client" },
  },
};

export default config;

client प्रीसेट प्लगइन्स का एक बंडल है जो एक ही बार में स्कीमा टाइप्स, ऑपरेशन टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स बनाता है। सेटअप और कॉन्फ़िगरेशन सेक्शंस में मैं इन सभी को कवर करूंगा।

GraphQL Codegen कैसे सेट अप करें

Codegen को समझने का सबसे अच्छा तरीका इसे किसी वास्तविक प्रोजेक्ट पर चलाना है।

इस सेक्शन में, आप शुरुआत से एक छोटा कोर्स कैटलॉग प्रोजेक्ट बनाएंगे। इसमें कोर्स और इंस्ट्रक्टर वाला एक स्कीमा, एक क्वेरी, और एक Codegen कॉन्फ़िग है जो क्वेरी को TypeScript टाइप्स में बदल देता है। आपको केवल Node.js और npm चाहिए।

कदम 1: GraphQL Code Generator इंस्टॉल करें

एक नया फ़ोल्डर बनाएं और एक npm प्रोजेक्ट इनिशियलाइज़ करें:

mkdir course-catalog && cd course-catalog
npm init -y

Codegen को कुछ पैकेजों की ज़रूरत होती है। दो रेगुलर डिपेंडेंसी में जाते हैं, और बाकी देव डिपेंडेंसी हैं क्योंकि वे केवल डेवलपमेंट के दौरान चलते हैं:

npm install graphql @graphql-typed-document-node/core
npm install -D typescript @graphql-codegen/cli @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node

हर पैकेज क्या करता है, यह रहा:

  • graphql: JavaScript के लिए रेफरेंस GraphQL इम्प्लीमेंटेशन, जिसका उपयोग Codegen स्कीमा और ऑपरेशंस को पार्स करने के लिए करता है

  • @graphql-typed-document-node/core: TypedDocumentNode टाइप प्रदान करता है जिसे आपका जनरेटेड कोड इम्पोर्ट करता है

  • @graphql-codegen/cli: Codegen कमांड-लाइन टूल

  • @graphql-codegen/typescript-operations: प्लगइन जो आपकी क्वेरी, म्यूटेशन और फ़्रैगमेंट्स के लिए टाइप्स जनरेट करता है

  • @graphql-codegen/typed-document-node: प्लगइन जो टाइप्स संलग्न किए हुए डॉक्यूमेंट ऑब्जेक्ट्स जनरेट करता है

कदम 2: एक कॉन्फ़िगरेशन फ़ाइल बनाएं

Codegen अपनी सेटिंग्स प्रोजेक्ट रूट में एक कॉन्फ़िग फ़ाइल से पढ़ता है। अभी के लिए एक खाली कॉन्फ़िग के साथ codegen.ts बनाएं:

import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {};

export default config;

आप npx graphql-codegen init भी चला सकते हैं ताकि कुछ सवालों के जवाब देकर एक जनरेटेड कॉन्फ़िग फ़ाइल मिल जाए। मैं इसे यहाँ हाथ से लिख रहा हूँ ताकि आप हर सेटिंग का काम देख सकें।

कदम 3: स्कीमा और डॉक्यूमेंट लोकेशंस निर्दिष्ट करें

Codegen को दो इनपुट चाहिए, तो दोनों बनाते हैं।

पहले, स्कीमा को प्रोजेक्ट रूट में schema.graphql के रूप में सेव करें:

enum Level {
  BEGINNER
  INTERMEDIATE
  ADVANCED
}

type Instructor {
  id: ID!
  name: String!
  bio: String
}

type Course {
  id: ID!
  title: String!
  level: Level!
  durationHours: Int!
  instructor: Instructor!
}

type Enrollment {
  id: ID!
  course: Course!
  studentEmail: String!
}

type Query {
  courses(level: Level, limit: Int): [Course!]!
  course(id: ID!): Course
}

type Mutation {
  enrollStudent(courseId: ID!, studentEmail: String!): Enrollment!
}

फिर src/operations/courses.graphql बनाएं जिसमें एक क्वेरी हो जो कोर्स और उनके इंस्ट्रक्टर्स को फ़ेच करती है:

query GetCourses($level: Level, $limit: Int) {
  courses(level: $level, limit: $limit) {
    id
    title
    level
    instructor {
      name
    }
  }
}

अब Codegen को दोनों फ़ाइलों की ओर इंगित करें। schema की में स्कीमा पाथ जाता है, और documents में आपके ऑपरेशंस से मेल खाने वाला ग्लोब पैटर्न:

const config: CodegenConfig = {
  schema: "schema.graphql",
  documents: ["src/**/*.graphql"],
};

कदम 4: एक आउटपुट फ़ाइल चुनें

generates की Codegen को बताती है कि आउटपुट कहाँ लिखना है। इसके अंदर हर की एक फ़ाइल पाथ होता है:

const config: CodegenConfig = {
  schema: "schema.graphql",
  documents: ["src/**/*.graphql"],
  generates: {
    "src/generated/graphql.ts": {},
  },
};

यदि src/generated/ फ़ोल्डर मौजूद नहीं है, तो Codegen इसे बना देता है।

कदम 5: प्रासंगिक प्लगइन्स जोड़ें

बिना प्लगइन्स के आउटपुट फ़ाइल खाली रहती है। जो दो प्लगइन्स आपने इंस्टॉल किए हैं, उन्हें जोड़ें:

import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  schema: "schema.graphql",
  documents: ["src/**/*.graphql"],
  generates: {
    "src/generated/graphql.ts": {
      plugins: ["typescript-operations", "typed-document-node"],
    },
  },
};

export default config;

यदि आपने कोई पुराना ट्यूटोरियल फॉलो किया है, तो आपने शायद इस सूची में typescript प्लगइन भी देखा होगा। अब आप इसे हटा सकते हैं, क्योंकि typescript-operations अपने आप काम करता है और केवल उन्हीं Input, Enum और Operation टाइप्स को जनरेट करता है जिनका वास्तव में उपयोग होता है। यदि आप मौजूदा वर्शन पर दोनों को एक ही आउटपुट फ़ाइल में रखते हैं, तो TypeScript डुप्लीकेट डिक्लेरेशन एरर्स फेंकता है।

कदम 6: Codegen चलाएं

एक npm स्क्रिप्ट जोड़ें ताकि आपको कमांड याद न रखना पड़े:

npm pkg set scripts.codegen="graphql-codegen"

फिर इसे चलाएं:

npm run codegen

Codegen स्कीमा लोड करता है, क्वेरी को उसके अनुरूप वैलिडेट करता है, और आउटपुट लिखता है:

Codegen जनरेशन परिणाम

Codegen जनरेशन परिणाम

यदि कोई ऑपरेशन स्कीमा में मौजूद नहीं फ़ील्ड को रेफ़र करता है, तो यहीं रन फेल होगा और कोई फ़ाइल नहीं लिखी जाएगी।

कदम 7: जनरेटेड आउटपुट का निरीक्षण करें

src/generated/graphql.ts खोलें। आपको यह दिखाई देगा:

जनरेटेड आउटपुट

Codegen ने चार चीजें जनरेट की हैं:

  • Level: enum के लिए एक स्ट्रिंग यूनियन, जो केवल इसलिए बना क्योंकि क्वेरी इसका उपयोग करती है

  • GetCoursesQueryVariables: क्वेरी को पास किए जाने वाले वेरिएबल्स का टाइप, जहाँ दोनों वैकल्पिक हैं क्योंकि स्कीमा उन्हें आवश्यक के रूप में चिह्नित नहीं करता

  • GetCoursesQuery: रिस्पॉन्स का आकार, जिसमें केवल वही फ़ील्ड्स हैं जो क्वेरी मांगती है

  • GetCoursesDocument: टाइप्ड डॉक्यूमेंट नोड के रूप में पार्स की गई क्वेरी, जिसमें रिज़ल्ट और वेरिएबल टाइप्स जुड़े हैं

GetCoursesQuery को फिर देखें। इसमें durationHours या इंस्ट्रक्टर का bio शामिल नहीं है, क्योंकि क्वेरी उन्हें नहीं मांगती। यदि आप अपने कोड में course.durationHours पढ़ने की कोशिश करेंगे, तो आपको रनटाइम पर undefined के बजाय कंपाइल एरर मिलेगा।

और बस — पूरा सेटअप यही है: आप GraphQL लिखते हैं, और Codegen TypeScript लिखता है।

GraphQL Codegen को कैसे कॉन्फ़िगर करें

अधिकांश Codegen कॉन्फ़िग ऊपर वाले से बड़े दिखेंगे, लेकिन वे इन्हीं चार सेटिंग्स से बने होते हैं।

कॉन्फ़िग फ़ाइल codegen.ts, codegen.yml, या codegen.json हो सकती है। मैं TypeScript का उपयोग कर रहा हूँ क्योंकि आपको कॉन्फ़िग पर ही ऑटोकम्प्लीट और टाइप चेक्स मिलते हैं। सेटिंग्स हर फ़ॉर्मैट में समान हैं।

स्कीमा

schema की Codegen को बताती है कि आपका स्कीमा कहाँ है। यह कुछ वैकल्पिक स्रोत प्रकार स्वीकार करती है।

जब स्कीमा आपकी रिपॉज़िटरी में हो, तो लोकल फ़ाइल या ग्लोब पैटर्न काम करता है:

schema: "schema.graphql",
// or, for a schema split across files
schema: "schema/**/*.graphql",

जब स्कीमा चल रहे सर्वर पर हो, तो URL काम करता है। Codegen एंडपॉइंट पर एक introspection क्वेरी भेजता है, और आप ऑथेंटिकेशन के लिए हेडर्स पास कर सकते हैं:

schema: [
  {
    "https://api.example.com/graphql": {
      headers: { Authorization: Bearer ${process.env.API_TOKEN} },
    },
  },
],

URL विकल्प तभी काम करता है जब सर्वर पर introspection इनेबल हो। कई प्रोडक्शन APIs इसे बंद कर देते हैं, इसलिए CI के लिए रिपॉज़िटरी में कमिट किया हुआ स्कीमा फ़ाइल आमतौर पर सुरक्षित विकल्प है।

डॉक्यूमेंट्स

documents की Codegen को बताती है कि आपकी क्वेरी, म्यूटेशन, सब्सक्रिप्शन और फ़्रैगमेंट कहाँ मिलेंगे।

ऑपरेशंस .graphql फ़ाइलों में या TypeScript कोड में इनलाइन रखे जा सकते हैं। जब इनलाइन ऑपरेशंस gql टैग में लिपटे हों या /* GraphQL */ कमेंट के साथ चिह्नित हों, तब Codegen उन्हें ढूंढता है:

const EnrollStudent = /* GraphQL */ 
  mutation EnrollStudent($courseId: ID!, $studentEmail: String!) {
    enrollStudent(courseId: $courseId, studentEmail: $studentEmail) {
      id
      course {
        title
      }
    }
  }
;

दोनों फ़ाइल प्रकार स्कैन करने के लिए ग्लोब को व्यापक करें। एक नेगेटेड पैटर्न जोड़ें ताकि Codegen अपना ही आउटपुट स्कैन न करे:

documents: ["src/**/*.{graphql,ts}", "!src/generated/**"],

हर ऑपरेशन को एक यूनिक नाम दें। Codegen ऑपरेशन नामों से टाइप नाम बनाता है, तो EnrollStudent से EnrollStudentMutation और EnrollStudentMutationVariables बनते हैं।

Generates

generates की आउटपुट पाथ्स को मैप करती है कि उनमें क्या जाएगा। आपको जितने चाहें उतने आउटपुट टार्गेट्स रख सकते हैं, प्रत्येक अपने प्लगइन्स के साथ।

मान लें आप ऑपरेशन टाइप्स एक फ़ाइल में और पूरे स्कीमा टाइप्स दूसरी में चाहते हैं:

generates: {
  "src/generated/graphql.ts": {
    plugins: ["typescript-operations", "typed-document-node"],
    config: {
      useTypeImports: true,
    },
  },
  "src/generated/schema-types.ts": {
    plugins: ["typescript"],
  },
},

आउटपुट टार्गेट के अंदर का config ऑब्जेक्ट केवल उसी फ़ाइल पर लागू होता है। यहाँ, useTypeImports जनरेटेड फ़ाइल में import type का उपयोग कराता है, जिसकी कुछ बिल्ड सेटअप्स को आवश्यकता होती है। यदि आप config को रूट पर रखते हैं, तो यह हर आउटपुट पर लागू होता है।

आउटपुट पाथ एक ऐसा फ़ोल्डर भी हो सकता है जो स्लैश के साथ समाप्त होता है, जैसे "src/gql/"। प्रीसेट्स इसी फ़ॉर्मैट का प्रयोग करते हैं, क्योंकि वे एक से अधिक फ़ाइलें लिखते हैं।

प्लगइन्स

प्लगइन्स तय करते हैं कि क्या जनरेट होगा। Codegen स्कीमा और डॉक्यूमेंट्स लोड करता है, और हर प्लगइन उन्हें आउटपुट के एक हिस्से में बदल देता है।

TypeScript प्रोजेक्ट्स में आपको अक्सर ये प्लगइन्स दिखेंगे:

  • typescript-operations: आपकी क्वेरी, म्यूटेशन, सब्सक्रिप्शन और फ़्रैगमेंट्स के लिए टाइप्स, साथ ही वे enums और inputs जिनका वे उपयोग करते हैं

  • typed-document-node: रिज़ल्ट और वेरिएबल टाइप्स संलग्न किए हुए डॉक्यूमेंट ऑब्जेक्ट्स, जिन्हें अधिकांश GraphQL क्लायंट समझते हैं

  • typescript: स्कीमा के हर ऑब्जेक्ट, enum और input के टाइप्स, भले ही आपके ऑपरेशंस उनका उपयोग करें या नहीं

  • typescript-resolvers: सर्वर साइड पर रिज़ॉल्वर फ़ंक्शंस के लिए टाइप सिग्नेचर

एक प्रीसेट प्लगइन्स का बंडल होता है जिसमें समझदारी भरा डिफ़ॉल्ट कॉन्फ़िग रहता है। यह कैसे काम करता है सेक्शन का client प्रीसेट The Guild क्लायंट ऐप्स के लिए सुझाता है। यह अंदर से सुधरे हुए typescript-operations पर आधारित है, तो आपको बिना अतिरिक्त सेटअप के उसके लाभ मिलते हैं।

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

GraphQL Codegen क्या जनरेट कर सकता है?

Codegen से आपको क्या मिलता है, यह आपके चुने हुए प्लगइन्स पर निर्भर करता है।

उसी स्कीमा और ऑपरेशंस से सादा TypeScript टाइप्स भी बन सकते हैं और तैयार क्लायंट कोड भी। यहाँ वे आउटपुट्स हैं जिन्हें आप सबसे अधिक उपयोग करेंगे।

TypeScript टाइप्स

typescript प्लगइन आपके स्कीमा के हर ऑब्जेक्ट, enum और input के लिए एक टाइप बनाता है। कोर्स कैटलॉग के लिए Course टाइप कुछ ऐसा दिखेगा:

export type Course = {
  __typename?: 'Course';
  durationHours: Scalars['Int']['output'];
  id: Scalars['ID']['output'];
  instructor: Instructor;
  level: Level;
  title: Scalars['String']['output'];
};

ये टाइप्स पूरे स्कीमा का वर्णन करते हैं, जिससे वे सर्वर साइड, टेस्ट फ़िक्स्चर्स और यूटिलिटी फ़ंक्शंस में उपयोगी होते हैं, जो पूर्ण ऑब्जेक्ट्स के साथ काम करते हैं।

लेकिन क्लायंट कोड के लिए ये उतने उपयुक्त नहीं। Course टाइप कहता है कि हर फ़ील्ड मौजूद है, भले ही आपकी क्वेरी ने उनके लिए नहीं कहा हो।

ऑपरेशन टाइप्स

typescript-operations प्लगइन प्रति ऑपरेशन दो टाइप्स जनरेट करता है: एक रिज़ल्ट के लिए और एक वेरिएबल्स के लिए। यह क्वेरी और सब्सक्रिप्शन के लिए भी इसी तरह काम करता है।

यहाँ EnrollStudent म्यूटेशन के लिए यह क्या जनरेट करता है:

export type EnrollStudentMutationVariables = Exact<{
  courseId: string | number;
  studentEmail: string;
}>;

export type EnrollStudentMutation = { enrollStudent: { id: string, course: { title: string } } };

रिज़ल्ट टाइप चयन सेट से फ़ील्ड-दर-फ़ील्ड मेल खाता है। वेरिएबल्स टाइप Exact होता है, इसलिए TypeScript अतिरिक्त या गलत लिखे गए वेरिएबल्स को अस्वीकार करता है।

courseId वेरिएबल string और number दोनों स्वीकार करता है क्योंकि GraphQL का ID scalar इनपुट में दोनों स्वीकार करता है। v6 से, डिफ़ॉल्ट टाइप string | number है, जो क्लायंट केस के लिए सही टाइप है।

टाइप्ड डॉक्यूमेंट नोड्स

एक सामान्य DocumentNode पार्स की गई GraphQL क्वेरी होता है। इसे क्वेरी की संरचना का पता होता है, लेकिन यह नहीं जानता कि क्वेरी क्या लौटाती है या कौन-से वेरिएबल्स लेती है।

एक टाइप्ड डॉक्यूमेंट नोड में दोनों टाइप्स साथ होते हैं। typed-document-node प्लगइन प्रति ऑपरेशन एक जनरेट करता है:

export const GetCoursesDocument = { /* ... */ } as unknown as DocumentNode<GetCoursesQuery, GetCoursesQueryVariables>;

इस तरह, कोई भी फ़ंक्शन जो TypedDocumentNode स्वीकार करता है, केवल डॉक्यूमेंट से ही रिज़ल्ट और वेरिएबल टाइप्स का अनुमान लगा सकता है। आपको हाथ से जेनेरिक्स पास नहीं करने पड़ते, और आप गलत टाइप्स वाली क्वेरी को नहीं जोड़ सकते।

अधिकांश आधुनिक GraphQL क्लायंट्स टाइप्ड डॉक्यूमेंट नोड्स स्वीकार करते हैं, जिनमें Apollo Client, urql, और graphql-request शामिल हैं। आप इस लेख में आगे इन तीनों को काम करते हुए देखेंगे।

क्लायंट-विशिष्ट इंटीग्रेशंस

कुछ प्लगइन्स इससे भी आगे जाकर किसी विशेष क्लायंट या फ्रेमवर्क के लिए कोड जनरेट करते हैं। उदाहरण:

  • typescript-react-apollo: Apollo Client के लिए टाइप्ड React hooks जनरेट करता है

  • typescript-urql: urql के लिए टाइप्ड hooks और कम्पोनेंट्स जनरेट करता है

  • typescript-react-query: TanStack Query के लिए टाइप्ड hooks जनरेट करता है

  • typescript-graphql-request: एक टाइप्ड SDK जनरेट करता है जिसमें प्रति ऑपरेशन एक फ़ंक्शन होता है

ये सभी कम्युनिटी प्लगइन्स हैं। The Guild ने इन्हें अलग कम्युनिटी रिपॉज़िटरी में स्थानांतरित कर दिया है, इसलिए इनकी रिलीज़ गति कोर प्लगइन्स से अलग है।

अब इनकी ज़रूरत भी पहले से कम है। जब कोई क्लायंट टाइप्ड डॉक्यूमेंट नोड्स स्वीकार करता है, तो जनरेटेड hooks अधिक टाइप सेफ़्टी नहीं जोड़ते। उदाहरण के लिए, Apollo के अपने दस्तावेज़ typescript-operations प्लगइन की अनुशंसा करते हैं, जो केवल टाइप्स जनरेट करने पर केंद्रित है और अतिरिक्त रनटाइम कोड शामिल नहीं करता।

आम तौर पर, आपको ऑपरेशन टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स से शुरू करना चाहिए। फिर, केवल तब किसी क्लायंट-विशिष्ट प्लगइन को जोड़ें जब आपकी टीम को जनरेटेड hooks या SDK फ़ंक्शंस चाहिए हों।

TypeScript के साथ GraphQL Codegen

जनरेटेड टाइप्स तभी मायने रखते हैं जब वे गलतियों को पकड़ें, तो चलिए कुछ गलतियाँ करते हैं।

यह उदाहरण कोर्स कैटलॉग प्रोजेक्ट को दूसरी क्वेरी, एक छोटा हेल्पर जो इसे API को भेजता है, और रिज़ल्ट का उपयोग करने वाले कोड से बढ़ाता है। यह मानता है कि http://localhost:4000/graphql पर स्कीमा को इम्प्लीमेंट करने वाला एक GraphQL सर्वर चल रहा है।

यहाँ स्कीमा का वह हिस्सा है जिसका यह उदाहरण उपयोग करता है:

type Instructor {
  id: ID!
  name: String!
  bio: String
}

type Course {
  id: ID!
  title: String!
  level: Level!
  durationHours: Int!
  instructor: Instructor!
}

type Query {
  course(id: ID!): Course
}

यहाँ दो विवरण महत्त्वपूर्ण हैं। course फ़ील्ड ! के बिना Course लौटाता है, इसलिए जब ID मेल नहीं खाती तो यह null हो सकता है। इंस्ट्रक्टर का bio भी nullable है।

src/operations/course.graphql बनाएं जिसमें एक क्वेरी एक कोर्स फ़ेच करती है:

query GetCourse($id: ID!) {
  course(id: $id) {
    title
    durationHours
    instructor {
      name
      bio
    }
  }
}

npm run codegen फिर चलाएं। Codegen src/generated/graphql.ts में दो नए टाइप्स जोड़ देता है:

graphql.ts फ़ाइल की सामग्री

स्कीमा से nullability भी यथावत रहती है। course null हो सकता है, bio null हो सकता है, और id आवश्यक है क्योंकि क्वेरी इसे ID! के रूप में घोषित करती है।

अब एप्लिकेशन कोड की बारी। src/execute.ts बनाएं जिसमें कोई भी टाइप्ड डॉक्यूमेंट API को भेजने वाला हेल्पर हो:

import { print } from "graphql";
import type { TypedDocumentNode } from "@graphql-typed-document-node/core";

const API_URL = "http://localhost:4000/graphql";

export async function execute<TResult, TVariables>(
  document: TypedDocumentNode<TResult, TVariables>,
  variables: TVariables,
): Promise<TResult> {
  const response = await fetch(API_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query: print(document), variables }),
  });
  const { data, errors } = await response.json();
  if (errors?.length) {
    throw new Error(errors[0].message);
  }
  return data as TResult;
}

हेल्पर को कोर्स के बारे में कुछ नहीं पता। इसे दोनों टाइप्स उसी डॉक्यूमेंट से मिलते हैं जिसे आप पास करते हैं, और print() फ़ंक्शन डॉक्यूमेंट को रिक्वेस्ट के लिए फिर से क्वेरी स्ट्रिंग में बदल देता है।

फिर इसे src/course-details.ts में उपयोग करें:

import { execute } from "./execute";
import { GetCourseDocument, type GetCourseQuery } from "./generated/graphql";

function formatCourse(course: NonNullable<GetCourseQuery["course"]>): string {
  const bio = course.instructor.bio ?? "No bio yet";
  return course.title({course.durationHours}h) by ${course.instructor.name} - ${bio};
}

const { course } = await execute(GetCourseDocument, { id: "c1" });

if (course) {
  console.log(formatCourse(course));
} else {
  console.log("Course not found");
}

formatCourse() फ़ंक्शन अपने पैरामीटर टाइप को जनरेटेड क्वेरी टाइप से लेता है। NonNullable null केस हटा देता है, क्योंकि फ़ंक्शन केवल if चेक के बाद चलता है।

उदाहरण टॉप-लेवल await का उपयोग करता है, इसलिए package.json में "type": "module" सेट करें और इसे npx tsx src/course-details.ts से चलाएं:

GraphQL मॉक सर्वर को सफल कॉल

GraphQL मॉक सर्वर को सफल कॉल

अब, यह मानता है कि आपके पास GraphQL सर्वर चल रहा है। यहाँ एक मॉक सर्वर है जिसका मैंने उपयोग किया:

import { createServer } from "node:http";
import { readFileSync } from "node:fs";
import { createSchema, createYoga } from "graphql-yoga";

const instructors = [{ id: "i1", name: "Dario Radecic", bio: "Developer" }];

const courses = [
  { id: "c1", title: "Intro to GraphQL", level: "BEGINNER", durationHours: 4, instructor: instructors[0] },
  { id: "c2", title: "GraphQL Schema Design", level: "ADVANCED", durationHours: 6, instructor: instructors[0] },
];

const schema = createSchema({
  typeDefs: readFileSync("schema.graphql", "utf8"),
  resolvers: {
    Query: {
      courses: (_: unknown, args: { level?: string; limit?: number }) =>
        courses
          .filter((course) => !args.level || course.level === args.level)
          .slice(0, args.limit ?? undefined),
      course: (_: unknown, args: { id: string }) =>
        courses.find((course) => course.id === args.id) ?? null,
    },
    Mutation: {
      enrollStudent: (_: unknown, args: { courseId: string; studentEmail: string }) => ({
        id: "e1",
        course: courses.find((course) => course.id === args.courseId),
        studentEmail: args.studentEmail,
      }),
    },
  },
});

createServer(createYoga({ schema })).listen(4000, () => {
  console.log("Mock API running at http://localhost:4000/graphql");
});

अब इसे तोड़ने की कोशिश करें। src/course-details.ts खोलें और formatCourse() फ़ंक्शन के नीचे सब कुछ उन तीन गलतियों से बदलें जिन्हें हाथ से लिखे टाइप्स अक्सर छोड़ देते हैं:

// Missing the required id variable
await execute(GetCourseDocument, {});

const { course } = await execute(GetCourseDocument, { id: "c1" });

// Reading a field the query doesn't request
console.log(course?.level);

// Forgetting that course can be null
console.log(course.title);

फिर प्रोजेक्ट को टाइप-चेक करें:

npx tsc -p .

TypeScript कोड चलने से पहले ही तीनों को पकड़ लेता है:

TypeScript द्वारा पकड़ी गई त्रुटियाँ

TypeScript द्वारा पकड़ी गई त्रुटियाँ

यही है कि Codegen फ्रंटएंड और API के बीच मिसमैच को कैसे कम करता है। टाइप्स उसी स्कीमा से आते हैं जिसका सर्वर उपयोग करता है, इसलिए वे ऐसे फ़ील्ड्स का वर्णन नहीं कर सकते जो मौजूद ही नहीं या ऐसे nulls को मिस नहीं कर सकते जिन्हें सर्वर लौटा सकता है।

और सुरक्षा पहली रन के बाद रुकती नहीं। मान लें बैकएंड टीम durationHours को nullable कर देती है। आप फिर जनरेट करते हैं, टाइप number | null में बदल जाता है, और TypeScript उन हर लाइनों की ओर इशारा करता है जहाँ आपने number मान लिया था।

GraphQL क्लायंट्स के साथ GraphQL Codegen

Codegen रिक्वेस्ट नहीं भेजता। वह काम आपके GraphQL क्लायंट का है।

जनरेटेड टाइप्ड डॉक्यूमेंट नोड्स दोनों के बीच हैंडऑफ़ पॉइंट हैं। आप उन्हें क्लायंट को पास करते हैं, और क्लायंट टाइप्स का अनुमान लगा लेता है। नीचे दिए उदाहरणों में वही src/generated/graphql.ts फ़ाइल और पिछले सेक्शन के मॉक API का उपयोग होता है, इसलिए npx tsx mock/server.ts को अलग टर्मिनल में चालू रखें।

Apollo के साथ GraphQL Codegen

Apollo Client और उसके rxjs पीयर डिपेंडेंसी इंस्टॉल करें:

npm install @apollo/client rxjs

उदाहरण EnrollStudent म्यूटेशन भी चलाता है। इसे src/operations/enroll.graphql के रूप में सेव करें:

mutation EnrollStudent($courseId: ID!, $studentEmail: String!) {
  enrollStudent(courseId: $courseId, studentEmail: $studentEmail) {
    id
    course {
      title
    }
  }
}

Apollo के दस्तावेज़ भी Codegen के लिए दो कॉन्फ़िग विकल्प सुझाते हैं, क्योंकि Apollo Client हमेशा __typename फ़ील्ड्स शामिल करता है लेकिन उन्हें रूट टाइप्स में नहीं जोड़ता। इन्हें codegen.ts में आउटपुट टार्गेट में जोड़ें:

"src/generated/graphql.ts": {
  plugins: ["typescript-operations", "typed-document-node"],
  config: {
    nonOptionalTypename: true,
    skipTypeNameForRoot: true,
  },
},

इन विकल्पों के साथ, जनरेटेड रिज़ल्ट टाइप्स में हर ऑब्जेक्ट को एक आवश्यक __typename फ़ील्ड मिलता है, जैसे __typename: 'Course'। यह Apollo के कैश से लौटे डेटा से मेल खाता है।

npm run codegen फिर चलाएं ताकि नई म्यूटेशन और कॉन्फ़िग का पता चल जाए।

Apollo Client query() और mutate() में टाइप्ड डॉक्यूमेंट नोड्स स्वीकार करता है। इसे src/apollo.ts के रूप में सेव करें:

import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
import { EnrollStudentDocument, GetCoursesDocument } from "./generated/graphql";

const client = new ApolloClient({
  link: new HttpLink({ uri: "http://localhost:4000/graphql" }),
  cache: new InMemoryCache(),
});

const { data } = await client.query({
  query: GetCoursesDocument,
  variables: { level: "BEGINNER", limit: 5 },
});

data?.courses.forEach((course) => console.log(course.title));

const result = await client.mutate({
  mutation: EnrollStudentDocument,
  variables: { courseId: "c1", studentEmail: "student@example.com" },
});

console.log(result.data?.enrollStudent.course.title);

data ऑब्जेक्ट का टाइप GetCoursesQuery | undefined है, और TypeScript variables को GetCoursesQueryVariables के विरुद्ध चेक करता है। म्यूटेशन EnrollStudentMutation और उसके वेरिएबल्स के साथ भी इसी तरह काम करता है।

npx tsx src/apollo.ts से चलाएं:

Apollo आउटपुट

Apollo आउटपुट

पहली पंक्ति क्वेरी से आती है, क्योंकि वही एकमात्र beginner कोर्स है। दूसरी म्यूटेशन से, जो उस कोर्स का शीर्षक लौटाती है जिसमें छात्र ने नामांकन किया।

React hooks, जैसे useQuery() और useMutation(), भी टाइप्ड डॉक्यूमेंट नोड्स से इसी तरह टाइप्स का अनुमान लगाते हैं।

urql के साथ GraphQL Codegen

urql का कोर पैकेज इंस्टॉल करें:

npm install @urql/core

urql बॉक्स से बाहर ही टाइप्ड डॉक्यूमेंट नोड्स के साथ काम करता है। src/urql.ts में query() के पहले आर्ग्युमेंट के रूप में डॉक्यूमेंट पास करें:

import { Client, cacheExchange, fetchExchange } from "@urql/core";
import { GetCoursesDocument } from "./generated/graphql";

const client = new Client({
  url: "http://localhost:4000/graphql",
  exchanges: [cacheExchange, fetchExchange],
});

const result = await client
  .query(GetCoursesDocument, { level: "ADVANCED" })
  .toPromise();

if (result.error) {
  throw result.error;
}

result.data?.courses.forEach((course) => console.log(course.title));

दूसरा आर्ग्युमेंट क्वेरी वेरिएबल्स के रूप में टाइप्ड होता है, और result.data क्वेरी रिज़ल्ट के रूप में टाइप्ड होता है।

npx tsx src/urql.ts से चलाएं:

Urql आउटपुट

Urql आउटपुट

फ्रेमवर्क बाइंडिंग्स, जैसे React के लिए urql पैकेज में useQuery(), भी टाइप्ड डॉक्यूमेंट नोड्स स्वीकार करते हैं।

अन्य क्लायंट्स के साथ GraphQL Codegen

टाइप्ड रिज़ल्ट पाने के लिए आपको किसी फुल-फ़ीचर्ड क्लायंट की ज़रूरत नहीं।

graphql-request क्लायंट एक मिनिमल क्लायंट है जो एक रिक्वेस्ट भेजता है और डेटा लौटाता है। इसे इस कमांड से इंस्टॉल करें:

npm install graphql-request

यह टाइप्ड डॉक्यूमेंट नोड्स से Apollo और urql की तरह ही टाइप्स का अनुमान लगाता है। इसे src/graphql-request.ts के रूप में सेव करें:

import { request } from "graphql-request";
import { GetCourseDocument } from "./generated/graphql";

const { course } = await request(
  "http://localhost:4000/graphql",
  GetCourseDocument,
  { id: "c2" },
);

console.log(course?.title);

npx tsx src/graphql-request.ts से चलाएं:

GraphQL रिक्वेस्ट आउटपुट

GraphQL रिक्वेस्ट आउटपुट

यही विचार TanStack Query के साथ भी काम करता है। यह स्वयं GraphQL रिक्वेस्ट नहीं भेजता, इसलिए आप क्वेरी फ़ंक्शन के अंदर graphql-request या पिछले सेक्शन के execute() हेल्पर को कॉल करते हैं, और रिज़ल्ट टाइप आपके कोड तक पहुँच जाता है।

और यदि आपका क्लायंट बिल्कुल भी टाइप्ड डॉक्यूमेंट नोड्स सपोर्ट नहीं करता, तो भी आप साधारण ऑपरेशन टाइप्स का उपयोग कर सकते हैं। GetCourseQuery और GetCourseQueryVariables इम्पोर्ट करें और उन्हें जेनेरिक्स के रूप में पास करें। यह थोड़ा अधिक मैनुअल काम है, पर टाइप्स फिर भी स्कीमा से आते हैं।

GraphQL Codegen को ऑटोमैटिक रूप से कैसे चलाएँ

जनरेटेड टाइप्स तभी मदद करते हैं जब वे मौजूदा स्कीमा और ऑपरेशंस से मेल खाते हों।

यदि आप बदलाव के बाद Codegen चलाना भूल जाते हैं, तो टाइप्स उस कोड का वर्णन करते हैं जो अब मौजूद नहीं। यह हाथ से लिखे टाइप्स वाली वही ड्रिफ्ट समस्या है, बस कुछ अतिरिक्त कदमों के साथ। समाधान है कि इस मैनुअल कदम को वर्कफ़्लो से हटा दें।

npm स्क्रिप्ट्स

package.json में कुछ स्क्रिप्ट्स से शुरू करें, ताकि टीम का हर सदस्य Codegen एक ही तरीके से चलाए:

{
  "scripts": {
    "codegen": "graphql-codegen",
    "codegen:watch": "graphql-codegen --watch",
    "codegen:check": "graphql-codegen --check",
    "prebuild": "npm run codegen",
    "build": "tsc -p ."
  }
}

इस सेक्शन के बाकी हिस्से बताते हैं कि प्रत्येक का उपयोग किसलिए है।

वॉच मोड

वॉच मोड हर बार किसी वॉच्ड फ़ाइल में बदलाव होने पर Codegen को फिर चलाता है। इसे @parcel/watcher पैकेज चाहिए, जिसे Codegen आपके लिए इंस्टॉल नहीं करता:

npm install -D @parcel/watcher
npm run codegen:watch

यदि आप इंस्टॉल छोड़ देते हैं, तो Codegen एक बार चलेगा और वॉच करने के बजाय Failed to import @parcel/watcher प्रिंट करेगा।

वॉच मोड आपके ऑपरेशंस और लोकल स्कीमा फ़ाइल दोनों को ट्रैक करता है। यदि आप course.graphql में कोई फ़ील्ड जोड़ते हैं, तो एक सेकंड बाद वह फ़ील्ड GetCourseQuery में दिखाई देती है। यदि आप schema.graphql में durationHours को nullable कर देते हैं, तो टाइप number | null में बदल जाता है, और आपका एडिटर हर लाइन को फ़्लैग करता है जिसने number मान लिया था।

डेवलपमेंट के दौरान इसे अपने डेव सर्वर के साथ एक टर्मिनल में चलाए रखें।

बिल्ड से पहले जनरेट करें

npm build से पहले prebuild नाम की स्क्रिप्ट चलाता है। ऊपर दी गई स्क्रिप्ट्स के साथ, npm run build पहले टाइप्स फिर से जनरेट करता है और उसके बाद ही TypeScript कम्पाइलर चलाता है।

इस तरह, कोई बिल्ड कभी पुराने टाइप्स के साथ नहीं चलता, भले ही किसी ने बदलाव खींचने के बाद Codegen चलाना भूल गया हो।

CI/CD

--check फ़्लैग Codegen को ड्राई-रन मोड में चलाता है। यह कोई फ़ाइल नहीं लिखता, यह जो जनरेट करेगा उसकी तुलना डिस्क पर मौजूद से करता है और यदि कुछ भिन्न हो तो कोड 1 के साथ बाहर निकलता है।

GitHub Actions का एक न्यूनतम वर्कफ़्लो यहाँ है जो इसका उपयोग करता है:

name: CI

on: [push, pull_request]

jobs:
  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - run: npm ci
      - run: npm run codegen:check
      - run: npm run build

codegen:check स्टेप का अर्थ तभी है जब आप जनरेटेड फ़ाइलें रिपॉज़िटरी में कमिट करते हैं। यदि नहीं, तो उस स्टेप को हटा दें, क्योंकि npm run build वैसे भी prebuild हुक के माध्यम से सब कुछ पुनः जनरेट कर देता है।

जब स्कीमा बदले तो पुनः जनरेट करें

ऑपरेशंस आपकी रिपॉज़िटरी में बदलते हैं, इसलिए वॉच मोड और prebuild उन्हें कवर करते हैं। स्कीमा परिवर्तन कठिन होते हैं, क्योंकि वे आमतौर पर किसी दूसरी टीम से आते हैं।

आप उन्हें कैसे संभालते हैं, यह इस पर निर्भर करता है कि स्कीमा कहाँ है:

  • उसी रिपॉज़िटरी में स्कीमा फ़ाइल: वॉच मोड और CI बदलाव पकड़ लेते हैं, जो काम करने के लिए सबसे आसान सेटअप है
  • URL से स्कीमा: Codegen हर रन पर नवीनतम संस्करण फ़ेच करता है, इसलिए CI में codegen:check जैसे ही सर्वर का स्कीमा आपके कमिटेड आउटपुट से मेल नहीं खाएगा, फेल हो जाएगा
  • किसी दूसरी रिपॉज़िटरी द्वारा प्रकाशित स्कीमा: अपने बिल्ड के हिस्से के रूप में उसे कॉपी या डाउनलोड करें, फिर लोकल कॉपी पर Codegen चलाएँ

URL विकल्प में एक पेंच है। वॉच मोड फ़ाइल बदलावों पर प्रतिक्रिया देता है, इसलिए उसे रिमोट स्कीमा बदलने का पता नहीं चलता। आपको वे बदलाव अगली मैनुअल रन या CI जॉब पर ही दिखेंगे।

GraphQL Codegen बनाम हाथ से लिखे टाइप्स

दोनों तरीकों से आपको GraphQL डेटा के लिए TypeScript टाइप्स मिलते हैं, लेकिन कुछ अंतर हैं जिनसे आपको अवगत होना चाहिए।

हाथ से लिखे टाइप्स

हाथ से लिखे टाइप्स में, आप स्कीमा पढ़ते हैं और खुद उससे मिलते-जुलते इंटरफ़ेसेज़ लिखते हैं।

इससे आपको पूरा नियंत्रण मिलता है। आप टाइप्स को अपनी मर्ज़ी से नाम दे सकते हैं, कुछ ऑपरेशंस को मिलाकर एक साझा टाइप बना सकते हैं, या स्कीमा में नहीं मौजूद हेल्पर टाइप्स जोड़ सकते हैं।

लेकिन यह मैनुअल काम है। हर नया फ़ील्ड या बदला गया आर्ग्युमेंट मतलब आपको मिलते-जुलते टाइप को हाथ से ढूंढकर अपडेट करना होगा। और जब आप एक छोड़ देते हैं, तो कोई चेतावनी नहीं होती।

यहीं से ड्रिफ्ट आती है। परिचय वाले Course इंटरफ़ेस ने बैकएंड द्वारा title का नाम बदलने के बाद भी कंपाइल कर लिया, क्योंकि TypeScript केवल आपके कोड को आपके टाइप्स के विरुद्ध जाँचता है, API के विरुद्ध नहीं।

जनरेटेड टाइप्स

जनरेटेड टाइप्स उसी स्कीमा से आते हैं जिसका सर्वर उपयोग करता है, इसलिए वे डिज़ाइन से ही आपकी GraphQL डिफ़िनिशंस के साथ सिंक में रहते हैं। एक स्कीमा बदलाव और Codegen रन एक साथ हर प्रभावित टाइप अपडेट करता है।

आप बहुत कम कोड भी लिखते हैं। कोर्स कैटलॉग प्रोजेक्ट में तीन ऑपरेशंस हैं और उनके लिए हाथ से लिखे टाइप्स शून्य हैं।

और आपको लगभग मुफ्त में स्कीमा-ड्रिवेन डेवलपमेंट मिल जाता है। आप स्कीमा या ऑपरेशन बदलते हैं, फिर जनरेट करते हैं, और कम्पाइलर आपको हर उस चीज़ की सूची देता है जिसे बदलने की ज़रूरत है।

लेकिन याद रखें कि Codegen केवल वही दर्शाता है जो आप इसे देते हैं।

यदि स्कीमा हर फ़ील्ड को nullable चिह्नित करता है, तो आपके जनरेटेड टाइप्स | null चेक्स से भरे होंगे। यदि कोई ऑपरेशन 40 फ़ील्ड्स फ़ेच करता है जबकि पेज को पाँच चाहिए, तो जनरेटेड टाइप में 40 फ़ील्ड्स होंगे।

अंतर का एक त्वरित पुनर्कथन यहाँ है:

  हाथ से लिखे टाइप्स जनरेटेड टाइप्स
रखरखाव हर स्कीमा बदलाव पर मैनुअल हर बदलाव के बाद एक कमांड
स्कीमा ड्रिफ्ट संभव और चुपचाप जनरेशन या कंपाइल समय पर पकड़ी जाती
बोइलरप्लेट हर ऑपरेशन के साथ बढ़ता है हाथ से कुछ लिखना नहीं
कस्टम टाइप्स पर नियंत्रण पूर्ण प्लगइन कॉन्फ़िग विकल्पों तक सीमित
स्कीमा-ड्रिवेन डेवलपमेंट मैनुअल क्रॉस-चेकिंग कम्पाइलर हर प्रभावित लाइन दिखाता है

हाथ से लिखे टाइप्स की तुलना में Codegen

GraphQL Codegen बनाम GraphQL Introspection

दोनों को अक्सर मिलाया जाता है क्योंकि Codegen अक्सर introspection का उपयोग करता है। फिर भी वे अलग समस्याएँ हल करते हैं।

Introspection GraphQL स्पेसिफ़िकेशन की एक विशेषता है। कोई भी GraphQL सर्वर अपने स्कीमा के बारे में क्वेरीज़ का उत्तर विशेष फ़ील्ड्स जैसे __schema और __type के माध्यम से दे सकता है। रिज़ल्ट API द्वारा एक्सपोज़ किए गए हर टाइप, फ़ील्ड और आर्ग्युमेंट का JSON विवरण होता है।

सीधी भाषा में, introspection “यह API कैसा दिखता है?” सवाल का जवाब देती है।

Codegen “मेरे एप्लिकेशन को किस कोड की ज़रूरत है?” सवाल का जवाब देता है। यह स्कीमा जानकारी और आपके ऑपरेशंस लेता है, और TypeScript टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स लिखता है।

जब आप codegen.ts में schema को किसी URL पर सेट करते हैं, तो Codegen उस सर्वर को स्कीमा पाने के लिए एक introspection क्वेरी भेजता है। लोकल .graphql फ़ाइल के साथ, introspection होता ही नहीं।

Codegen आउटपुट के रूप में introspection रिज़ल्ट भी बना सकता है। @graphql-codegen/introspection प्लगइन स्कीमा को introspection JSON के रूप में लिखता है, जिसका उपयोग कुछ टूल्स, जैसे urql का Graphcache, स्कीमा-अवेयर कैशिंग के लिए करते हैं।

  Introspection GraphQL Codegen
क्या है बिल्ट-इन GraphQL क्वेरी सिस्टम कमांड-लाइन टूल और प्लगइन
इनपुट चलते सर्वर को भेजी गई क्वेरी एक स्कीमा और आपके ऑपरेशंस
आउटपुट स्कीमा का JSON विवरण टाइप्स, डॉक्यूमेंट नोड्स, क्लायंट कोड
कब चलता है जब भी कोई क्लायंट सर्वर से पूछे डेवलपमेंट, बिल्ड्स और CI के दौरान

Introspection की तुलना में Codegen

सामान्य GraphQL Codegen समस्याएँ

ज़्यादातर Codegen एरर्स चार में से किसी एक समस्या तक सिमटते हैं।

जनरेटेड टाइप्स गायब हैं

Codegen बिना एरर्स के चलता है, लेकिन जिस टाइप की आपको उम्मीद है वह आउटपुट फ़ाइल में नहीं है।

इन तीन बातों को क्रम से जाँचें:

  • स्कीमा: यदि टाइप उस स्कीमा में मौजूद ही नहीं है जिसे Codegen लोड करता है, तो उसे जनरेट नहीं किया जा सकता — तो स्कीमा फ़ाइल खोलें या खुद introspection क्वेरी चलाकर पुष्टि करें

  • डॉक्यूमेंट्स: ऑपरेशन टाइप्स केवल उन्हीं ऑपरेशंस के लिए मौजूद होते हैं जिन्हें Codegen ने ढूंढा। यदि आपकी क्वेरी वाली फ़ाइल documents ग्लोब से मैच नहीं होती, तो उसके टाइप्स गायब होंगे

  • प्लगइन्स: v6 से, typescript-operations केवल वे enums और inputs जनरेट करता है जिनका आपके ऑपरेशंस उपयोग करते हैं, तो यदि आपको Course जैसे पूरे स्कीमा टाइप की ज़रूरत है, typescript प्लगइन को अलग आउटपुट फ़ाइल में जोड़ें

यदि आप कोई ऐसा प्लगइन उपयोग करते हैं जिसे आपने इंस्टॉल नहीं किया, तो Codegen स्पष्ट संदेश के साथ फेल होता है:

Unable to find template plugin matching 'typescript-react-apollo'
Install one of the following packages:
- @graphql-codegen/typescript-react-apollo

Codegen को ऑपरेशंस नहीं मिल रहे

यह एरर बताता है कि documents ग्लोब किसी भी ऐसी फ़ाइल से मेल नहीं खाया जिसमें ऑपरेशन हो:

Unable to find any GraphQL type definitions for the following pointers:
  - src/**/*.gql

देखें कि ग्लोब में एक्सटेंशन आपकी फ़ाइलों से मेल खाता है या नहीं। .gql पैटर्न .graphql फ़ाइलें नहीं ढूंढेगा, और src/**/*.graphql पैटर्न .ts फ़ाइलों में इनलाइन ऑपरेशंस नहीं ढूंढेगा।

इनलाइन ऑपरेशंस के लिए टैग भी चेक करें। Codegen केवल gql में लिपटे टेम्पलेट लिटरेल्स या /* GraphQL */ कमेंट से चिह्नित टेम्पलेट्स ढूंढता है। सादा टेम्पलेट स्ट्रिंग जिसमें अंदर क्वेरी हो, यह नहीं देखता।

यदि आप ignoreNoDocuments: true सेट करते हैं, तो Codegen यह एरर नहीं दिखाता और ऑपरेशन टाइप्स के बिना आउटपुट जनरेट करता है। यह विकल्प एक बिल्कुल नए प्रोजेक्ट में उपयोगी है, लेकिन बाद में यह किसी टूटे ग्लोब को छिपा सकता है।

जनरेटेड टाइप्स पुराने हैं

टाइप्स कंपाइल हो जाते हैं, लेकिन वे ऑपरेशन या स्कीमा के नवीनतम बदलाव को दर्शाते नहीं।

Codegen अपने आप नहीं चलता। हर .graphql फ़ाइल, इनलाइन ऑपरेशन, स्कीमा या codegen.ts में बदलाव के बाद इसे फिर चलाएँ। डेवलपमेंट के दौरान, npm run codegen:watch यह आपके लिए करता है।

यदि CI में टाइप्स पुराने हैं, तो जनरेटेड फ़ाइलें कमिट करें या prebuild हुक से बिल्ड से पहले उन्हें पुनः जनरेट होने दें।

जनरेटेड टाइप्स API से मेल नहीं खाते

टाइप्स कंपाइल हो जाते हैं, लेकिन रनटाइम पर सर्वर से डेटा का आकार अलग होता है।

अक्सर इसका मतलब होता है कि Codegen और आपका ऐप अलग स्कीमा से बात कर रहे हैं। उदाहरण के लिए, Codegen लोकल schema.graphql पढ़ता है जो एक हफ्ते पुराना है, जबकि ऐप ऐसे प्रोडक्शन API को कॉल करता है जो तब से बदल चुका है।

देखें कि schema की कहाँ पॉइंट करती है। यदि यह फ़ाइल है, तो इसकी तुलना उस API से करें जिसे आपका ऐप कॉल करता है, और इसे अपडेट करें। यदि यह URL है, तो सुनिश्चित करें कि यह वही एनवायरनमेंट है जिसका आपका ऐप उपयोग करता है, कोई नया या पुराना स्कीमा वाला स्टेजिंग सर्वर नहीं।

फिर पुनः जनरेट करें और डिफ़ देखें। यदि कोई ऑपरेशन फ़ाइल बदली लेकिन जनरेटेड फ़ाइल नहीं, तो ऑपरेशन शायद documents ग्लोब के बाहर है।

GraphQL Codegen के लिए सर्वोत्तम प्रथाएँ

Codegen को अच्छे से काम करने के लिए बहुत अधिक कॉन्फ़िगरेशन नहीं चाहिए। ये प्रथाएँ प्रोजेक्ट बढ़ने पर भी इसे सरल रखती हैं:

  • स्कीमा और जनरेटेड फ़ाइलों को सिंक में रखें: डेवलपमेंट के दौरान वॉच मोड और बिल्ड से पहले prebuild चलाएँ, ताकि कोई भी पुराने स्कीमा से आए टाइप्स के साथ काम न करे

  • ऑपरेशन-विशिष्ट टाइप्स जनरेट करें: क्लायंट कोड के लिए typescript-operations का उपयोग करें क्योंकि वे बिल्कुल वही मेल खाते हैं जो हर क्वेरी फ़ेच करती है

  • जनरेटेड फ़ाइलें केवल तब कमिट करें जब आपके वर्कफ़्लो को उनकी ज़रूरत हो: कमिटेड फ़ाइलें आपको पुल रिक्वेस्ट्स में टाइप बदलावों की समीक्षा करने और CI में --check चलाने देती हैं; और यदि आपकी टीम को इसकी ज़रूरत नहीं, तो आउटपुट फ़ोल्डर को .gitignore में जोड़ें और हर बिल्ड पर जनरेट करें

  • कॉन्फ़िग छोटा रखें: दो प्लगइन्स के साथ एक आउटपुट फ़ाइल अधिकांश क्लायंट प्रोजेक्ट्स को कवर कर देती है, और हर अतिरिक्त विकल्प अगला डेवलपर कुछ भी बदलने से पहले समझना पड़ेगा

  • हर पुश पर CI में Codegen चलाएँ: --check स्टेप या prebuild हुक उन बदलावों को पकड़ता है जिन्हें किसी ने लोकली पुनः जनरेट करना भूल गया

  • जनरेटेड फ़ाइलों को कभी हाथ से एडिट न करें: अगला Codegen रन आपके बदलावों को ओवरराइट कर देगा, इसलिए स्कीमा, ऑपरेशन या कॉन्फ़िग को ठीक करें

निष्कर्ष

GraphQL Codegen GraphQL डेवलपमेंट के सबसे दोहराए जाने वाले हिस्से — स्कीमा और ऑपरेशंस को हाथ से TypeScript टाइप्स में बदलना — को अपने हाथ में लेता है।

वर्कफ़्लो प्रोजेक्ट कितना भी बड़ा हो, वैसा ही रहता है। आप स्कीमा और ऑपरेशंस परिभाषित करते हैं, Codegen कॉन्फ़िगर करते हैं, टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स जनरेट करते हैं, और उन्हें अपने एप्लिकेशन कोड में इम्पोर्ट करते हैं।

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

यदि आप सीखना चाहते हैं कि एक आधुनिक NoSQL डेटाबेस में GraphQL का उपयोग कैसे होता है, तो हमारा MongoDB और GraphQL ब्लॉग पोस्ट पढ़ें।


Dario Radečić's photo
Author
Dario Radečić
LinkedIn
क्रोएशिया में स्थित सीनियर डेटा साइंटिस्ट। 700 से अधिक प्रकाशित लेखों के साथ टॉप टेक राइटर, जिनसे 10M+ व्यूज़ प्राप्त हुए। Machine Learning Automation with TPOT के पुस्तक लेखक।

GraphQL Codegen FAQs

GraphQL Codegen का उपयोग किस लिए होता है?

GraphQL Codegen एक GraphQL स्कीमा और आपके GraphQL ऑपरेशंस से कोड जनरेट करता है। अधिकांश टीमें इसे अपनी क्वेरी और म्यूटेशन के लिए TypeScript टाइप्स और टाइप्ड डॉक्यूमेंट नोड्स पाने के लिए उपयोग करती हैं, ताकि उन्हें वे टाइप्स हाथ से लिखने और अपडेट करने न पड़ें। यह सर्वर के लिए रिज़ॉल्वर टाइप्स और विशेष क्लायंट्स के लिए तैयार hooks भी जनरेट कर सकता है।

क्या Codegen उपयोग करने के लिए मुझे चल रहा GraphQL सर्वर चाहिए?

नहीं। Codegen स्कीमा को लोकल .graphql फ़ाइल से पढ़ सकता है, इसलिए यह बिना किसी सर्वर के काम करता है। आपको केवल तब चल रहे सर्वर की ज़रूरत होती है जब आप schema की को किसी URL पर इंगित करते हैं, क्योंकि तब Codegen introspection के माध्यम से स्कीमा फ़ेच करता है।

क्या मुझे जनरेटेड फ़ाइलें Git में कमिट करनी चाहिए?

यह आपकी टीम के वर्कफ़्लो पर निर्भर करता है। कमिट की गई फ़ाइलें आपको पुल रिक्वेस्ट्स में टाइप बदलाव रिव्यू करने देती हैं और CI में graphql-codegen --check से बासी आउटपुट पकड़ने देती हैं। यदि इसकी ज़रूरत नहीं, तो आउटपुट फ़ोल्डर को .gitignore में जोड़ें और हर बिल्ड से पहले फ़ाइलें पुनः जनरेट करें।

मुझे client प्रीसेट इस्तेमाल करना चाहिए या अलग-अलग प्लगइन्स?

The Guild अधिकांश क्लायंट ऐप्स के लिए client प्रीसेट की अनुशंसा करता है, क्योंकि यह एक ही सेटअप में ऑपरेशन टाइप्स, टाइप्ड डॉक्यूमेंट नोड्स और फ़्रैगमेंट मास्किंग को बंडल करता है। Apollo client प्रीसेट के बजाय typescript-operations प्लगइन की सलाह देता है, क्योंकि प्रीसेट रनटाइम कोड और ऐसी सुविधाएँ जोड़ता है जो Apollo Client से टकरा सकती हैं। यदि आप Apollo का उपयोग करते हैं, तो प्लगइन्स चुनें। अन्यथा, प्रीसेट एक अच्छा डिफ़ॉल्ट है।

Codegen अपडेट करने के बाद मुझे duplicate declaration एरर्स क्यों मिल रहे हैं?

v6 से, typescript-operations प्लगइन अपने enums और input टाइप्स खुद जनरेट करता है। यदि आपकी कॉन्फ़िग अब भी उसी आउटपुट फ़ाइल के लिए typescript और typescript-operations दोनों लिस्ट करती है, तो दोनों प्लगइन Level जैसे टाइप्स डिक्लेयर करेंगे, और TypeScript डुप्लीकेट डिक्लेरेशन एरर्स फेंकेगा। उस आउटपुट से typescript प्लगइन हटा दें, या यदि आपको अब भी पूरा स्कीमा टाइप्स चाहिए तो उसे अलग फ़ाइल में ले जाएँ।

विषय

DataCamp के साथ सीखें

कोर्स

Software Development with Claude Code

4 घंटा
8.8K
Claude Code brings AI assistance to your terminal. Learn the workflows that turn it into a reliable tool for real software development.
विवरण देखेंRight Arrow
पाठ्यक्रम शुरू करें

लर्निंग पाथ

सॉफ्टवेयर इंजीनियरिंग के लिए Python

32 घंटा
सॉफ़्टवेयर इंजीनियरिंग के लिए Python कौशल विकसित करें। स्वच्छ फ़ंक्शन लिखें, OOP, डेटा संरचनाएँ और एल्गोरिदम में महारत हासिल करें, और अच्छी तरह से परीक्षण किया गया कोड तैयार करें.

लर्निंग पाथ

सॉफ़्टवेयर इंजीनियरिंग के लिए AI

7 घंटा
GitHub Copilot, Windsurf और Replit सहित नवीनतम AI डेवलपर टूल्स के साथ पहले से कहीं तेज़ कोड लिखें और सॉफ़्टवेयर एप्लिकेशन बनाएं।
और देखेंRight Arrow