nitro-graphql 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,82 +7,51 @@
7
7
  [![bundle][bundle-src]][bundle-href]
8
8
  [![License][license-src]][license-href]
9
9
 
10
- **A standalone Nitro module that integrates GraphQL servers into any Nitro application with automatic type generation, file watching, and seamless framework integration.**
10
+ **The easiest way to add GraphQL to any Nitro application**
11
11
 
12
- [🚀 Quick Start](#-quick-start)[📖 Documentation](#-documentation)[🎮 Playground](#-playground)[💬 Community](#-community--contributing)
12
+ 🚀 **Auto-discovery**📝 **Type Generation** • 🎮 **Apollo Sandbox** 🔧 **Zero Config**
13
+
14
+ [Quick Start](#-quick-start) • [Examples](#-examples) • [Documentation](#-documentation) • [Community](#-community)
13
15
 
14
16
  </div>
15
17
 
16
18
  ---
17
19
 
18
- *"GraphQL is not just a query language; it's a new way to think about APIs and client-server interaction."*
19
-
20
- ## ✨ Features
21
-
22
- - 🚀 **Multi-Framework Support**: Works with GraphQL Yoga and Apollo Server
23
- - 🔧 **Auto-Discovery**: Automatically scans and loads GraphQL schema and resolver files
24
- - 📝 **Type Generation**: Automatic TypeScript type generation from GraphQL schemas (server & client)
25
- - 🎮 **Apollo Sandbox**: Built-in GraphQL playground for development
26
- - 🏥 **Health Check**: Built-in health check endpoint
27
- - 🔌 **Universal Compatibility**: Works with any Nitro-based application (Nuxt, standalone Nitro, etc.)
28
- - 🎯 **Zero Configuration**: Sensible defaults with optional customization
29
- - 📂 **File-Based Organization**: Domain-driven resolver and schema organization
30
- - 🔄 **Hot Reload**: Development mode with automatic schema and resolver updates
31
- - 📦 **Optimized Bundling**: Smart chunking and dynamic imports for production
32
- - 🌐 **Nuxt Integration**: First-class Nuxt.js support with dedicated module
33
- - 🎭 **Custom Directives**: Create reusable GraphQL directives with automatic schema generation
34
- - 🔗 **Multi-Service Support**: Connect to multiple external GraphQL APIs alongside your main server
35
-
36
- ## 🎯 Used Projects
20
+ ## 🎥 Watch & Learn
37
21
 
38
- Projects using Nitro GraphQL in production:
22
+ - [**Nuxt 4 Integration**](https://x.com/productdevbook/status/1947314569531076633) - Step-by-step Nuxt setup
23
+ - [**Standalone Nitro**](https://x.com/productdevbook/status/1945759751393976348) - Basic Nitro integration
39
24
 
40
- - [**Nitroping**](https://github.com/productdevbook/nitroping) - Open-source, self-hosted push notification service
25
+ ## Why Nitro GraphQL?
41
26
 
42
- ## 🎥 Video Tutorials
27
+ - **5-minute setup** - From zero to GraphQL in minutes
28
+ - 🔍 **Auto-discovery** - Scans your files, builds your schema
29
+ - 📝 **Type-safe** - Full TypeScript support with auto-generated types
30
+ - 🎯 **Universal** - Works with Nuxt, Nitro, and any Nitro-based framework
31
+ - 🎮 **Developer-friendly** - Built-in Apollo Sandbox for testing
32
+ - 🔧 **Zero config** - Sensible defaults, customize when needed
43
33
 
44
- Learn how to use Nitro GraphQL with these video tutorials:
34
+ ## 🚀 Quick Start
45
35
 
46
- - [**Nuxt 4 Usage**](https://x.com/productdevbook/status/1947314569531076633) - How to integrate Nitro GraphQL with Nuxt 4
47
- - [**Nitro Usage**](https://x.com/productdevbook/status/1945759751393976348) - How to use Nitro GraphQL with standalone Nitro
36
+ ### 1. Install
48
37
 
49
- ## 🎯 Quick Start
50
-
51
- ### Step 1: Installation
52
-
53
- Choose your GraphQL framework and install required dependencies:
54
-
55
- **For GraphQL Yoga:**
38
+ **GraphQL Yoga (recommended):**
56
39
  ```bash
57
- # npm
58
- npm install nitro-graphql graphql-yoga graphql
59
-
60
- # pnpm (recommended)
61
40
  pnpm add nitro-graphql graphql-yoga graphql
62
-
63
- # yarn
64
- yarn add nitro-graphql graphql-yoga graphql
65
41
  ```
66
42
 
67
- **For Apollo Server:**
43
+ **Apollo Server:**
68
44
  ```bash
69
- # npm
70
- npm install nitro-graphql @apollo/server @apollo/utils.withrequired @as-integrations/h3 graphql
71
-
72
- # pnpm (recommended)
73
45
  pnpm add nitro-graphql @apollo/server @apollo/utils.withrequired @as-integrations/h3 graphql
74
-
75
- # yarn
76
- yarn add nitro-graphql @apollo/server @apollo/utils.withrequired @as-integrations/h3 graphql
77
46
  ```
78
47
 
79
- ### Step 2: Setup Your Project
48
+ ### 2. Configure
80
49
 
81
50
  <details>
82
- <summary>🔧 <strong>For Standalone Nitro Projects</strong></summary>
51
+ <summary>🔧 <strong>Nitro Project</strong></summary>
83
52
 
84
- 1. **Update your `nitro.config.ts`:**
85
53
  ```ts
54
+ // nitro.config.ts
86
55
  import { defineNitroConfig } from 'nitropack/config'
87
56
 
88
57
  export default defineNitroConfig({
@@ -93,24 +62,16 @@ export default defineNitroConfig({
93
62
  })
94
63
  ```
95
64
 
96
- 2. **Create the GraphQL directory structure:**
97
- ```bash
98
- mkdir -p server/graphql
99
- ```
100
-
101
65
  </details>
102
66
 
103
67
  <details>
104
- <summary>🟢 <strong>For Nuxt.js Projects</strong></summary>
68
+ <summary>🟢 <strong>Nuxt Project</strong></summary>
105
69
 
106
- 1. **Update your `nuxt.config.ts`:**
107
70
  ```ts
71
+ // nuxt.config.ts
108
72
  export default defineNuxtConfig({
109
- modules: [
110
- 'nitro-graphql/nuxt',
111
- ],
73
+ modules: ['nitro-graphql/nuxt'],
112
74
  nitro: {
113
- modules: ['nitro-graphql'],
114
75
  graphql: {
115
76
  framework: 'graphql-yoga',
116
77
  },
@@ -118,22 +79,12 @@ export default defineNuxtConfig({
118
79
  })
119
80
  ```
120
81
 
121
- 2. **Create the GraphQL directory structure:**
122
- ```bash
123
- mkdir -p server/graphql
124
- ```
125
-
126
82
  </details>
127
83
 
128
- ### Step 3: Create Your First Schema
129
-
130
- Create your main schema file:
84
+ ### 3. Create Your Schema
131
85
 
132
86
  ```graphql
133
87
  # server/graphql/schema.graphql
134
- scalar DateTime
135
- scalar JSON
136
-
137
88
  type Query {
138
89
  hello: String!
139
90
  greeting(name: String!): String!
@@ -144,84 +95,44 @@ type Mutation {
144
95
  }
145
96
  ```
146
97
 
147
- ### Step 4: Create Your First Resolver
148
-
149
- Create a resolver for your queries:
98
+ ### 4. Add Resolvers
150
99
 
151
100
  ```ts
152
101
  // server/graphql/hello.resolver.ts
153
- import { defineResolver } from 'nitro-graphql/utils/define'
154
-
155
102
  export const helloResolver = defineResolver({
156
103
  Query: {
157
104
  hello: () => 'Hello from GraphQL!',
158
105
  greeting: (_, { name }) => `Hello, ${name}!`,
159
106
  },
160
107
  })
161
-
162
- // You can also export multiple resolvers from the same file
163
- export const additionalResolver = defineResolver({
164
- Query: {
165
- // Additional query resolvers
166
- },
167
- })
168
108
  ```
169
109
 
170
- ### Step 5: Start Your Server
110
+ ### 5. Start Development
171
111
 
172
112
  ```bash
173
- # For Nitro
174
- pnpm dev
175
-
176
- # For Nuxt
177
113
  pnpm dev
178
114
  ```
179
115
 
180
- ### Step 6: Test Your GraphQL API
181
-
182
- 🎉 **That's it!** Your GraphQL server is now running at:
183
-
184
- - **GraphQL Endpoint**: `http://localhost:3000/api/graphql`
185
- - **Apollo Sandbox**: `http://localhost:3000/api/graphql` (in browser)
186
- - **Health Check**: `http://localhost:3000/api/graphql/health`
187
-
188
- ## 📖 Documentation
189
-
190
- ### Project Structure
191
-
192
- The module uses a domain-driven file structure under `server/graphql/`:
116
+ 🎉 **That's it!** Your GraphQL server is ready at:
117
+ - **Endpoint**: `http://localhost:3000/api/graphql`
118
+ - **Playground**: `http://localhost:3000/api/graphql` (browser)
119
+ - **Health**: `http://localhost:3000/api/graphql/health`
193
120
 
194
- ```
195
- server/
196
- ├── graphql/
197
- │ ├── schema.graphql # Main schema with scalars and base types
198
- │ ├── hello.resolver.ts # Global resolvers (use named exports)
199
- │ ├── directives/ # Custom GraphQL directives
200
- │ │ ├── auth.directive.ts # Authentication directive
201
- │ │ ├── cache.directive.ts # Caching directive
202
- │ │ └── validate.directive.ts # Validation directive
203
- │ ├── users/
204
- │ │ ├── user.graphql # User schema definitions
205
- │ │ ├── user-queries.resolver.ts # User query resolvers (use named exports)
206
- │ │ └── create-user.resolver.ts # User mutation resolvers (use named exports)
207
- │ ├── posts/
208
- │ │ ├── post.graphql # Post schema definitions
209
- │ │ ├── post-queries.resolver.ts # Post query resolvers (use named exports)
210
- │ │ └── create-post.resolver.ts # Post mutation resolvers (use named exports)
211
- │ └── config.ts # Optional GraphQL configuration
212
- │ └── schema.ts # Changing Special Return types
213
- ```
121
+ ## 🎮 Examples
214
122
 
215
- > [!TIP]
216
- > **New Named Export Pattern**: The module now supports named exports for GraphQL resolvers, allowing you to export multiple resolvers from a single file. This provides better organization and flexibility in structuring your resolver code.
123
+ Try these working examples:
217
124
 
218
- ### Building Your First Feature
125
+ | Example | Description | Demo |
126
+ |---------|-------------|------|
127
+ | [**Nitro Basic**](./playgrounds/nitro/) | Standalone Nitro with GraphQL | `pnpm playground:nitro` |
128
+ | [**Nuxt Integration**](./playgrounds/nuxt/) | Full Nuxt app with client types | `pnpm playground:nuxt` |
129
+ | [**Apollo Federation**](./playgrounds/federation/) | Federated GraphQL services | `pnpm playground:federation` |
219
130
 
220
- Let's create a complete user management feature:
131
+ ## 🏗️ Building Your First Feature
221
132
 
222
- <details>
223
- <summary>👤 <strong>Step 1: Define User Schema</strong></summary>
133
+ Let's create a complete user management system:
224
134
 
135
+ ### 1. Define Schema
225
136
  ```graphql
226
137
  # server/graphql/users/user.graphql
227
138
  type User {
@@ -246,15 +157,9 @@ extend type Mutation {
246
157
  }
247
158
  ```
248
159
 
249
- </details>
250
-
251
- <details>
252
- <summary>🔍 <strong>Step 2: Create Query Resolvers</strong></summary>
253
-
160
+ ### 2. Create Resolvers
254
161
  ```ts
255
- // server/graphql/users/user-queries.resolver.ts
256
- import { defineQuery } from 'nitro-graphql/utils/define'
257
-
162
+ // server/graphql/users/user.resolver.ts
258
163
  export const userQueries = defineQuery({
259
164
  users: async (_, __, { storage }) => {
260
165
  return await storage.getItem('users') || []
@@ -265,25 +170,7 @@ export const userQueries = defineQuery({
265
170
  }
266
171
  })
267
172
 
268
- // You can also split queries into separate named exports
269
- export const additionalUserQueries = defineQuery({
270
- userCount: async (_, __, { storage }) => {
271
- const users = await storage.getItem('users') || []
272
- return users.length
273
- },
274
- })
275
- ```
276
-
277
- </details>
278
-
279
- <details>
280
- <summary>✏️ <strong>Step 3: Create Mutation Resolvers</strong></summary>
281
-
282
- ```ts
283
- // server/graphql/users/create-user.resolver.ts
284
- import { defineMutation } from 'nitro-graphql/utils/define'
285
-
286
- export const createUserMutation = defineMutation({
173
+ export const userMutations = defineMutation({
287
174
  createUser: async (_, { input }, { storage }) => {
288
175
  const users = await storage.getItem('users') || []
289
176
  const user = {
@@ -296,31 +183,10 @@ export const createUserMutation = defineMutation({
296
183
  return user
297
184
  }
298
185
  })
299
-
300
- // You can also export multiple mutations from the same file
301
- export const updateUserMutation = defineMutation({
302
- updateUser: async (_, { id, input }, { storage }) => {
303
- const users = await storage.getItem('users') || []
304
- const userIndex = users.findIndex(user => user.id === id)
305
- if (userIndex === -1)
306
- throw new Error('User not found')
307
-
308
- users[userIndex] = { ...users[userIndex], ...input }
309
- await storage.setItem('users', users)
310
- return users[userIndex]
311
- }
312
- })
313
186
  ```
314
187
 
315
- </details>
316
-
317
- <details>
318
- <summary>🧪 <strong>Step 4: Test Your Feature</strong></summary>
319
-
320
- Open Apollo Sandbox at `http://localhost:3000/api/graphql` and try:
321
-
188
+ ### 3. Test in Apollo Sandbox
322
189
  ```graphql
323
- # Create a user
324
190
  mutation {
325
191
  createUser(input: {
326
192
  name: "John Doe"
@@ -333,7 +199,6 @@ mutation {
333
199
  }
334
200
  }
335
201
 
336
- # Query users
337
202
  query {
338
203
  users {
339
204
  id
@@ -343,89 +208,58 @@ query {
343
208
  }
344
209
  ```
345
210
 
346
- </details>
347
-
348
- ### Type Generation
349
-
350
- The module automatically generates TypeScript types for you:
351
-
352
- - **Server types**: `.nitro/types/nitro-graphql-server.d.ts`
353
- - **Client types**: `.nitro/types/nitro-graphql-client.d.ts`
354
- - **Auto-imports**: Available for `defineResolver` and other utilities
211
+ ## 🚀 Advanced Features
355
212
 
356
- Your IDE will automatically provide type safety and autocomplete!
357
-
358
- #### Using Generated Types
213
+ <details>
214
+ <summary><strong>🎭 Custom Directives</strong></summary>
359
215
 
360
- You can import and use the generated types in your code:
216
+ Create reusable GraphQL directives:
361
217
 
362
- **Client-side types** (`#graphql/client`):
363
218
  ```ts
364
- // Import generated types for queries, mutations, and operations
365
- import type { GetUsersQuery, CreateUserInput } from '#graphql/client'
366
-
367
- // Use in Vue components
368
- const users = ref<GetUsersQuery['users']>([])
369
-
370
- // Use in composables
371
- export function useUsers() {
372
- const createUser = async (input: CreateUserInput) => {
373
- // Type-safe input
219
+ // server/graphql/directives/auth.directive.ts
220
+ export const authDirective = defineDirective({
221
+ name: 'auth',
222
+ locations: ['FIELD_DEFINITION'],
223
+ args: {
224
+ requires: { type: 'String', defaultValue: 'USER' }
225
+ },
226
+ transformer: (schema) => {
227
+ // Add authentication logic
374
228
  }
375
- }
229
+ })
376
230
  ```
377
231
 
378
- **Server-side types** (`#graphql/server`):
379
- ```ts
380
- // Import generated types and interfaces
381
- import type { User, Post, CreateUserInput } from '#graphql/server'
382
-
383
- // Use types in your server code
384
- function validateUser(user: User): boolean {
385
- return user.email.includes('@')
386
- }
387
-
388
- // Use in data layer
389
- async function getUserPosts(user: User): Promise<Post[]> {
390
- // user is fully typed with all fields
391
- return await db.posts.findMany({ where: { authorId: user.id } })
392
- }
393
-
394
- // Use input types for validation
395
- function validateCreateUserInput(input: CreateUserInput): void {
396
- if (!input.email || !input.name) {
397
- throw new Error('Email and name are required')
398
- }
232
+ Use in schema:
233
+ ```graphql
234
+ type Query {
235
+ users: [User!]! @auth(requires: "ADMIN")
236
+ profile: User! @auth
399
237
  }
400
238
  ```
401
239
 
402
- These imports provide full TypeScript support with autocompletion, type checking, and IntelliSense in your IDE.
403
-
404
- > [!TIP]
405
- > **Nitro Auto-Imports**: Thanks to Nitro's auto-import feature, you don't need to manually import `defineResolver`, `defineQuery`, `defineMutation`, and other utilities in your resolver files. They're available globally! However, if you prefer explicit imports, you can use:
406
- > ```ts
407
- > import { defineResolver } from 'nitro-graphql/utils/define'
408
- > ```
409
-
410
- ### Configuration
240
+ </details>
411
241
 
412
242
  <details>
413
- <summary>⚙️ <strong>Runtime Configuration</strong></summary>
243
+ <summary><strong>🌐 External GraphQL Services</strong></summary>
244
+
245
+ Connect to multiple GraphQL APIs:
414
246
 
415
247
  ```ts
416
- // nitro.config.ts
417
- export default defineNitroConfig({
418
- modules: ['nitro-graphql'],
419
- graphql: {
420
- framework: 'graphql-yoga', // or 'apollo-server'
421
- },
422
- runtimeConfig: {
248
+ // nuxt.config.ts
249
+ export default defineNuxtConfig({
250
+ nitro: {
423
251
  graphql: {
424
- endpoint: {
425
- graphql: '/api/graphql', // GraphQL endpoint
426
- healthCheck: '/api/graphql/health' // Health check endpoint
427
- },
428
- playground: true, // Enable Apollo Sandbox
252
+ framework: 'graphql-yoga',
253
+ externalServices: [
254
+ {
255
+ name: 'github',
256
+ schema: 'https://api.github.com/graphql',
257
+ endpoint: 'https://api.github.com/graphql',
258
+ headers: () => ({
259
+ Authorization: `Bearer ${process.env.GITHUB_TOKEN}`
260
+ })
261
+ }
262
+ ]
429
263
  }
430
264
  }
431
265
  })
@@ -434,1123 +268,155 @@ export default defineNitroConfig({
434
268
  </details>
435
269
 
436
270
  <details>
437
- <summary>🔧 <strong>Advanced Configuration</strong></summary>
271
+ <summary><strong>🔄 Apollo Federation</strong></summary>
272
+
273
+ Build federated GraphQL services:
438
274
 
439
275
  ```ts
440
- // server/graphql/config.ts
441
- import { defineGraphQLConfig } from 'nitro-graphql/utils/define'
442
-
443
- export default defineGraphQLConfig({
444
- // Custom GraphQL Yoga or Apollo Server configuration
445
- plugins: [
446
- // Add custom plugins
447
- ],
448
- context: async ({ request }) => {
449
- // Enhanced context with custom properties
450
- return {
451
- user: await authenticateUser(request),
452
- db: await connectDatabase(),
276
+ // nitro.config.ts
277
+ export default defineNitroConfig({
278
+ graphql: {
279
+ framework: 'apollo-server',
280
+ federation: {
281
+ enabled: true,
282
+ serviceName: 'users-service'
453
283
  }
454
- },
284
+ }
455
285
  })
456
286
  ```
457
287
 
458
288
  </details>
459
289
 
460
- ## 🎮 Playground
461
-
462
- Try out the examples:
463
-
464
- - **Standalone Nitro**: [`playground/`](playground/)
465
- - **Nuxt.js Integration**: [`playground-nuxt/`](playground-nuxt/)
466
-
467
- Both examples include working GraphQL schemas, resolvers, and demonstrate the module's capabilities.
468
-
469
- ## 🔧 API Reference
290
+ ## 📖 Documentation
470
291
 
471
292
  ### Core Utilities
472
293
 
473
- > [!NOTE]
474
- > **Auto-Import Available**: All utilities are automatically imported in your resolver files thanks to Nitro's auto-import feature. You can use them directly without import statements, or use explicit imports if you prefer:
475
- > ```ts
476
- > import { defineMutation, defineQuery, defineResolver } from 'nitro-graphql/utils/define'
477
- > ```
294
+ All utilities are auto-imported in resolver files:
478
295
 
479
- > [!IMPORTANT]
480
- > **Named Exports Required**: All GraphQL resolvers must now use named exports instead of default exports. This allows you to export multiple resolvers from a single file, providing better organization and flexibility. For example:
481
- > ```ts
482
- > // Correct - Named exports
483
- > export const userQueries = defineQuery({ ... })
484
- > export const userMutations = defineMutation({ ... })
485
- >
486
- > // ❌ Incorrect - Default exports (deprecated)
487
- > export default defineQuery({ ... })
488
- > ```
296
+ | Function | Purpose | Example |
297
+ |----------|---------|---------|
298
+ | `defineResolver` | Complete resolvers | `defineResolver({ Query: {...}, Mutation: {...} })` |
299
+ | `defineQuery` | Query-only resolvers | `defineQuery({ users: () => [...] })` |
300
+ | `defineMutation` | Mutation-only resolvers | `defineMutation({ createUser: (...) => {...} })` |
301
+ | `defineType` | Custom type resolvers | `defineType({ User: { posts: (parent) => [...] } })` |
302
+ | `defineDirective` | Custom directives | `defineDirective({ name: 'auth', ... })` |
489
303
 
490
- <details>
491
- <summary><strong>defineResolver</strong> - Define complete resolvers</summary>
304
+ ### Type Generation
492
305
 
493
- ```ts
494
- import { defineResolver } from 'nitro-graphql/utils/define'
306
+ Automatic TypeScript types are generated:
307
+ - **Server types**: `#graphql/server` - Use in resolvers and server code
308
+ - **Client types**: `#graphql/client` - Use in frontend components
495
309
 
496
- export const mainResolver = defineResolver({
497
- Query: {
498
- // Query resolvers
499
- },
500
- Mutation: {
501
- // Mutation resolvers
502
- },
503
- // Custom type resolvers
504
- })
310
+ ```ts
311
+ // Server-side
312
+ import type { User, CreateUserInput } from '#graphql/server'
505
313
 
506
- // You can also export multiple resolvers from the same file
507
- export const additionalResolver = defineResolver({
508
- Query: {
509
- // Additional query resolvers
510
- },
511
- })
314
+ // Client-side
315
+ import type { GetUsersQuery, CreateUserMutation } from '#graphql/client'
512
316
  ```
513
317
 
514
- </details>
515
-
516
- <details>
517
- <summary><strong>defineQuery</strong> - Define only Query resolvers</summary>
518
-
519
- ```ts
520
- import { defineQuery } from 'nitro-graphql/utils/define'
521
-
522
- export const userQueries = defineQuery({
523
- users: async (_, __, { storage }) => {
524
- return await storage.getItem('users') || []
525
- },
526
- user: async (_, { id }, { storage }) => {
527
- const users = await storage.getItem('users') || []
528
- return users.find(user => user.id === id)
529
- }
530
- })
318
+ ### Project Structure
531
319
 
532
- // You can also split queries into separate named exports
533
- export const userStatsQueries = defineQuery({
534
- userCount: async (_, __, { storage }) => {
535
- const users = await storage.getItem('users') || []
536
- return users.length
537
- },
538
- })
320
+ ```
321
+ server/
322
+ ├── graphql/
323
+ │ ├── schema.graphql # Main schema
324
+ │ ├── hello.resolver.ts # Basic resolvers
325
+ │ ├── users/
326
+ │ │ ├── user.graphql # User schema
327
+ │ │ └── user.resolver.ts # User resolvers
328
+ │ ├── directives/ # Custom directives
329
+ │ └── config.ts # Optional GraphQL config
539
330
  ```
540
331
 
541
- </details>
332
+ > **⚠️ Important**: Use **named exports** for all resolvers:
333
+ > ```ts
334
+ > // ✅ Correct
335
+ > export const userQueries = defineQuery({...})
336
+ >
337
+ > // ❌ Deprecated
338
+ > export default defineQuery({...})
339
+ > ```
542
340
 
543
- <details>
544
- <summary><strong>defineMutation</strong> - Define only Mutation resolvers</summary>
341
+ ## 🚨 Troubleshooting
545
342
 
546
- ```ts
547
- import { defineMutation } from 'nitro-graphql/utils/define'
343
+ <details>
344
+ <summary><strong>Common Issues</strong></summary>
548
345
 
549
- export const userMutations = defineMutation({
550
- createUser: async (_, { input }, { storage }) => {
551
- const users = await storage.getItem('users') || []
552
- const user = {
553
- id: Date.now().toString(),
554
- ...input,
555
- createdAt: new Date()
556
- }
557
- users.push(user)
558
- await storage.setItem('users', users)
559
- return user
560
- }
561
- })
346
+ **GraphQL endpoint returns 404**
347
+ - Check `nitro-graphql` is in modules
348
+ - Set `graphql.framework` option
349
+ - Create at least one `.graphql` file
562
350
 
563
- // You can also export multiple mutations from the same file
564
- export const userUpdateMutations = defineMutation({
565
- updateUser: async (_, { id, input }, { storage }) => {
566
- const users = await storage.getItem('users') || []
567
- const userIndex = users.findIndex(user => user.id === id)
568
- if (userIndex === -1)
569
- throw new Error('User not found')
351
+ **Types not generating**
352
+ - Restart dev server
353
+ - Check file naming: `*.graphql`, `*.resolver.ts`
354
+ - Verify exports are named exports
570
355
 
571
- users[userIndex] = { ...users[userIndex], ...input }
572
- await storage.setItem('users', users)
573
- return users[userIndex]
574
- }
575
- })
576
- ```
356
+ **Import errors**
357
+ - Use correct path: `nitro-graphql/utils/define`
358
+ - ✅ Use named exports in resolvers
577
359
 
578
360
  </details>
579
361
 
580
- <details>
581
- <summary><strong>defineSubscription</strong> - Define Subscription resolvers</summary>
362
+ ## 🌟 Production Usage
582
363
 
583
- ```ts
584
- import { defineSubscription } from 'nitro-graphql/utils/define'
364
+ This package powers production applications:
585
365
 
586
- export const userSubscriptions = defineSubscription({
587
- userAdded: {
588
- subscribe: () => pubsub.asyncIterator('USER_ADDED'),
589
- },
590
- postUpdated: {
591
- subscribe: withFilter(
592
- () => pubsub.asyncIterator('POST_UPDATED'),
593
- (payload, variables) => payload.postUpdated.id === variables.postId
594
- ),
595
- }
596
- })
366
+ - [**Nitroping**](https://github.com/productdevbook/nitroping) - Self-hosted push notification service
597
367
 
598
- // You can also export multiple subscriptions from the same file
599
- export const notificationSubscriptions = defineSubscription({
600
- notificationAdded: {
601
- subscribe: () => pubsub.asyncIterator('NOTIFICATION_ADDED'),
602
- },
603
- })
604
- ```
368
+ ## 🛠️ Development
605
369
 
606
- </details>
370
+ ```bash
371
+ # Install dependencies
372
+ pnpm install
607
373
 
608
- <details>
609
- <summary><strong>defineType</strong> - Define custom type resolvers</summary>
374
+ # Build module
375
+ pnpm build
610
376
 
611
- ```ts
612
- import { defineType } from 'nitro-graphql/utils/define'
377
+ # Watch mode
378
+ pnpm dev
613
379
 
614
- export const userTypes = defineType({
615
- User: {
616
- posts: async (parent, _, { storage }) => {
617
- const posts = await storage.getItem('posts') || []
618
- return posts.filter(post => post.authorId === parent.id)
619
- },
620
- fullName: parent => `${parent.firstName} ${parent.lastName}`,
621
- },
622
- })
380
+ # Run playgrounds
381
+ pnpm playground:nitro
382
+ pnpm playground:nuxt
383
+ pnpm playground:federation
623
384
 
624
- // You can also export multiple type resolvers from the same file
625
- export const postTypes = defineType({
626
- Post: {
627
- author: async (parent, _, { storage }) => {
628
- const users = await storage.getItem('users') || []
629
- return users.find(user => user.id === parent.authorId)
630
- },
631
- },
632
- })
385
+ # Lint
386
+ pnpm lint
633
387
  ```
634
388
 
635
- </details>
389
+ ## 💬 Community
636
390
 
637
- <details>
638
- <summary><strong>defineDirective</strong> - Create custom GraphQL directives</summary>
391
+ > [!TIP]
392
+ > **Want to contribute?** We believe you can play a role in the growth of this project!
639
393
 
640
- ```ts
641
- import { defineDirective } from 'nitro-graphql/utils/define'
642
- import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
643
- import { defaultFieldResolver, GraphQLError } from 'graphql'
394
+ ### Ways to Contribute
395
+ - 💡 **Share ideas** via [GitHub Issues](https://github.com/productdevbook/nitro-graphql/issues)
396
+ - 🐛 **Report bugs** with detailed information
397
+ - 📖 **Improve docs** - README, examples, guides
398
+ - 🔧 **Code contributions** - Bug fixes and features
399
+ - 🌟 **Star the project** to show support
644
400
 
645
- export const authDirective = defineDirective({
646
- name: 'auth',
647
- locations: ['FIELD_DEFINITION', 'OBJECT'],
648
- args: {
649
- requires: {
650
- type: 'String',
651
- defaultValue: 'USER',
652
- description: 'Required role to access this field',
653
- },
654
- },
655
- description: 'Directive to check authentication and authorization',
656
- transformer: (schema) => {
657
- return mapSchema(schema, {
658
- [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
659
- const authDirectiveConfig = getDirective(schema, fieldConfig, 'auth')?.[0]
660
-
661
- if (authDirectiveConfig) {
662
- const { resolve = defaultFieldResolver } = fieldConfig
663
-
664
- fieldConfig.resolve = async function (source, args, context, info) {
665
- if (!context.user) {
666
- throw new GraphQLError('You must be logged in')
667
- }
668
-
669
- if (context.user.role !== authDirectiveConfig.requires) {
670
- throw new GraphQLError('Insufficient permissions')
671
- }
672
-
673
- return resolve(source, args, context, info)
674
- }
675
- }
676
-
677
- return fieldConfig
678
- },
679
- })
680
- },
681
- })
682
- ```
401
+ ### Help Wanted
402
+ - [ ] Performance benchmarks
403
+ - [ ] Video tutorials
404
+ - [ ] Database adapter guides
405
+ - [ ] VS Code extension
683
406
 
684
- **Usage in Schema:**
685
- ```graphql
686
- type User {
687
- id: ID!
688
- name: String!
689
- email: String! @auth(requires: "ADMIN")
690
- secretData: String @auth(requires: "SUPER_ADMIN")
691
- }
407
+ ## Sponsors
692
408
 
693
- type Query {
694
- users: [User!]! @auth
695
- adminStats: AdminStats @auth(requires: "ADMIN")
696
- }
697
- ```
409
+ <p align="center">
410
+ <a href="https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg">
411
+ <img src='https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg?t=1721043966'/>
412
+ </a>
413
+ </p>
698
414
 
699
- **Available Argument Types:**
700
- - Basic scalars: `String`, `Int`, `Float`, `Boolean`, `ID`, `JSON`, `DateTime`
701
- - Non-nullable: `String!`, `Int!`, `Float!`, `Boolean!`, `ID!`, `JSON!`, `DateTime!`
702
- - Arrays: `[String]`, `[String!]`, `[String]!`, `[String!]!` (and all combinations for other types)
703
- - Custom types: Any string for your custom GraphQL types
704
-
705
- **Helper Function:**
706
- ```ts
707
- export const validateDirective = defineDirective({
708
- name: 'validate',
709
- locations: ['FIELD_DEFINITION', 'ARGUMENT_DEFINITION'],
710
- args: {
711
- minLength: arg('Int', { description: 'Minimum length' }),
712
- maxLength: arg('Int', { description: 'Maximum length' }),
713
- pattern: arg('String', { description: 'Regex pattern' }),
714
- },
715
- // ... transformer implementation
716
- })
717
- ```
718
-
719
- </details>
720
-
721
- <details>
722
- <summary><strong>defineSchema</strong> - Define custom schema with validation</summary>
723
-
724
- You can override schema types if needed. StandardSchema supported — Zod, Valibot, anything works:
725
-
726
- ```ts
727
- # server/graphql/schema.ts
728
- import { defineSchema } from 'nitro-graphql/utils/define'
729
- import { z } from 'zod'
730
-
731
- export default defineSchema({
732
- Todo: z.object({
733
- id: z.string(),
734
- title: z.string(),
735
- completed: z.boolean(),
736
- createdAt: z.date(),
737
- }),
738
- User: z.object({
739
- id: z.string(),
740
- name: z.string(),
741
- email: z.string().email(),
742
- age: z.number().min(0),
743
- }),
744
- })
745
- ```
746
-
747
- **With Drizzle Schema:**
748
- ```ts
749
- import { defineSchema } from 'nitro-graphql/utils/define'
750
- import { z } from 'zod'
751
- import { userSchema } from './drizzle/user'
752
-
753
- export default defineSchema({
754
- Todo: z.object({
755
- id: z.string(),
756
- title: z.string(),
757
- }),
758
- User: userSchema, // Import from Drizzle schema
759
- })
760
- ```
761
-
762
- </details>
763
-
764
- ## 🚨 Troubleshooting
765
-
766
- <details>
767
- <summary><strong>Common Issues</strong></summary>
768
-
769
- ### GraphQL endpoint returns 404
770
-
771
- **Solution**: Make sure you have:
772
- 1. Added `nitro-graphql` to your modules
773
- 2. Set the `graphql.framework` option
774
- 3. Created at least one schema file
775
-
776
- ### Types not generating
777
-
778
- **Solution**:
779
- 1. Restart your dev server
780
- 2. Check that your schema files end with `.graphql`
781
- 3. Verify your resolver files end with `.resolver.ts`
782
-
783
- ### Hot reload not working
784
-
785
- **Solution**:
786
- 1. Make sure you're in development mode
787
- 2. Check file naming conventions
788
- 3. Restart the dev server
789
-
790
- ### Import errors with utilities
791
-
792
- **Solution**:
793
- ```ts
794
- // ❌ Incorrect import path
795
- import { defineResolver } from 'nitro-graphql'
796
-
797
- // ✅ Correct import path
798
- import { defineResolver } from 'nitro-graphql/utils/define'
799
- ```
800
-
801
- ### Export pattern errors
802
-
803
- **Solution**:
804
- ```ts
805
- // ❌ Incorrect - Default exports (deprecated)
806
- export default defineResolver({ ... })
807
-
808
- // ✅ Correct - Named exports
809
- export const myResolver = defineResolver({ ... })
810
- export const anotherResolver = defineResolver({ ... })
811
- ```
812
-
813
- </details>
814
-
815
- ## 🌟 Framework Support
816
-
817
- <details>
818
- <summary><strong>GraphQL Yoga</strong></summary>
819
-
820
- ```ts
821
- // nitro.config.ts
822
- export default defineNitroConfig({
823
- graphql: {
824
- framework: 'graphql-yoga',
825
- },
826
- })
827
- ```
828
-
829
- </details>
830
-
831
- <details>
832
- <summary><strong>Apollo Server</strong></summary>
833
-
834
- ```ts
835
- // nitro.config.ts
836
- export default defineNitroConfig({
837
- graphql: {
838
- framework: 'apollo-server',
839
- },
840
- })
841
- ```
842
-
843
- </details>
844
-
845
- ## 🔥 Advanced Features
846
-
847
- <details>
848
- <summary><strong>Custom Directives</strong></summary>
849
-
850
- Create reusable GraphQL directives with automatic schema generation:
851
-
852
- ```ts
853
- // server/graphql/directives/auth.directive.ts
854
- import { defineDirective } from 'nitro-graphql/utils/define'
855
- import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
856
-
857
- export const authDirective = defineDirective({
858
- name: 'auth',
859
- locations: ['FIELD_DEFINITION', 'OBJECT'],
860
- args: {
861
- requires: {
862
- type: 'String',
863
- defaultValue: 'USER',
864
- description: 'Required role to access this field',
865
- },
866
- },
867
- description: 'Authentication and authorization directive',
868
- transformer: (schema) => {
869
- return mapSchema(schema, {
870
- [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
871
- const authConfig = getDirective(schema, fieldConfig, 'auth')?.[0]
872
- if (authConfig) {
873
- // Transform field resolvers to check authentication
874
- const { resolve = defaultFieldResolver } = fieldConfig
875
- fieldConfig.resolve = async (source, args, context, info) => {
876
- if (!context.user || context.user.role !== authConfig.requires) {
877
- throw new GraphQLError('Access denied')
878
- }
879
- return resolve(source, args, context, info)
880
- }
881
- }
882
- return fieldConfig
883
- },
884
- })
885
- },
886
- })
887
- ```
888
-
889
- **Common Directive Examples:**
890
- - `@auth(requires: "ADMIN")` - Role-based authentication
891
- - `@cache(ttl: 300, scope: "PUBLIC")` - Field-level caching
892
- - `@rateLimit(limit: 10, window: 60)` - Rate limiting
893
- - `@validate(minLength: 5, maxLength: 100)` - Input validation
894
- - `@transform(upper: true, trim: true)` - Data transformation
895
- - `@permission(roles: ["ADMIN", "MODERATOR"])` - Multi-role permissions
896
-
897
- **Usage in Schema:**
898
- ```graphql
899
- type User {
900
- id: ID!
901
- name: String!
902
- email: String! @auth(requires: "ADMIN")
903
- posts: [Post!]! @cache(ttl: 300)
904
- }
905
-
906
- type Query {
907
- users: [User!]! @rateLimit(limit: 100, window: 3600)
908
- sensitiveData: String @auth(requires: "SUPER_ADMIN")
909
- }
910
- ```
911
-
912
- The module automatically generates the directive schema definitions and integrates them with both GraphQL Yoga and Apollo Server.
913
-
914
- </details>
915
-
916
- <details>
917
- <summary><strong>Custom Scalars</strong></summary>
918
-
919
- ```ts
920
- // server/graphql/scalars/DateTime.resolver.ts
921
- import { GraphQLScalarType } from 'graphql'
922
- import { Kind } from 'graphql/language'
923
- import { defineResolver } from 'nitro-graphql/utils/define'
924
-
925
- export const dateTimeScalar = defineResolver({
926
- DateTime: new GraphQLScalarType({
927
- name: 'DateTime',
928
- serialize: (value: Date) => value.toISOString(),
929
- parseValue: (value: string) => new Date(value),
930
- parseLiteral: (ast) => {
931
- if (ast.kind === Kind.STRING) {
932
- return new Date(ast.value)
933
- }
934
- return null
935
- }
936
- })
937
- })
938
-
939
- // You can also export multiple scalars from the same file
940
- export const jsonScalar = defineResolver({
941
- JSON: new GraphQLScalarType({
942
- name: 'JSON',
943
- serialize: value => value,
944
- parseValue: value => value,
945
- parseLiteral: (ast) => {
946
- if (ast.kind === Kind.STRING) {
947
- return JSON.parse(ast.value)
948
- }
949
- return null
950
- }
951
- })
952
- })
953
- ```
954
-
955
- </details>
956
-
957
- <details>
958
- <summary><strong>Error Handling</strong></summary>
959
-
960
- ```ts
961
- // server/graphql/users/user-queries.resolver.ts
962
- import { defineQuery } from 'nitro-graphql/utils/define'
963
-
964
- export const userQueries = defineQuery({
965
- user: async (_, { id }, { storage }) => {
966
- try {
967
- const user = await storage.getItem(`user:${id}`)
968
- if (!user) {
969
- throw new Error(`User with id ${id} not found`)
970
- }
971
- return user
972
- }
973
- catch (error) {
974
- console.error('Error fetching user:', error)
975
- throw error
976
- }
977
- }
978
- })
979
-
980
- // You can also export additional error handling queries
981
- export const safeUserQueries = defineQuery({
982
- userSafe: async (_, { id }, { storage }) => {
983
- try {
984
- const user = await storage.getItem(`user:${id}`)
985
- return user || null // Return null instead of throwing
986
- }
987
- catch (error) {
988
- console.error('Error fetching user:', error)
989
- return null
990
- }
991
- }
992
- })
993
- ```
994
-
995
- </details>
996
-
997
- <details>
998
- <summary><strong>Nuxt Integration</strong></summary>
999
-
1000
- For Nuxt.js applications, the module provides enhanced integration:
1001
-
1002
- ```ts
1003
- // nuxt.config.ts
1004
- export default defineNuxtConfig({
1005
- modules: [
1006
- 'nitro-graphql/nuxt',
1007
- ],
1008
- nitro: {
1009
- modules: ['nitro-graphql'],
1010
- graphql: {
1011
- framework: 'graphql-yoga',
1012
- },
1013
- },
1014
- })
1015
- ```
1016
-
1017
- Client-side GraphQL files are automatically detected in the `app/graphql/` directory.
1018
-
1019
- ### Client-Side Usage
1020
-
1021
- The module automatically generates a GraphQL SDK and provides type-safe client access for frontend usage.
1022
-
1023
- <details>
1024
- <summary>📁 <strong>GraphQL File Structure</strong></summary>
1025
-
1026
- Create your GraphQL queries and mutations in the `app/graphql/` directory:
1027
-
1028
- ```
1029
- app/
1030
- ├── graphql/
1031
- │ ├── queries.graphql # GraphQL queries
1032
- │ ├── mutations.graphql # GraphQL mutations
1033
- │ └── subscriptions.graphql # GraphQL subscriptions (optional)
1034
- ```
1035
-
1036
- </details>
1037
-
1038
- <details>
1039
- <summary>🔥 <strong>Creating GraphQL Files</strong></summary>
1040
-
1041
- **Query File Example:**
1042
- ```graphql
1043
- # app/graphql/queries.graphql
1044
- query GetUsers {
1045
- users {
1046
- id
1047
- name
1048
- email
1049
- createdAt
1050
- }
1051
- }
1052
-
1053
- query GetUser($id: ID!) {
1054
- user(id: $id) {
1055
- id
1056
- name
1057
- email
1058
- createdAt
1059
- }
1060
- }
1061
- ```
1062
-
1063
- **Mutation File Example:**
1064
- ```graphql
1065
- # app/graphql/mutations.graphql
1066
- mutation CreateUser($input: CreateUserInput!) {
1067
- createUser(input: $input) {
1068
- id
1069
- name
1070
- email
1071
- createdAt
1072
- }
1073
- }
1074
-
1075
- mutation UpdateUser($id: ID!, $input: UpdateUserInput!) {
1076
- updateUser(id: $id, input: $input) {
1077
- id
1078
- name
1079
- email
1080
- createdAt
1081
- }
1082
- }
1083
- ```
1084
-
1085
- </details>
1086
-
1087
- <details>
1088
- <summary>⚡ <strong>Using the Generated SDK</strong></summary>
1089
-
1090
- The module automatically generates a type-safe SDK based on your GraphQL files:
1091
-
1092
- ```ts
1093
- // The SDK is automatically generated and available as an import
1094
- import { createGraphQLClient } from '#graphql/client'
1095
-
1096
- // Create a client instance
1097
- const client = createGraphQLClient({
1098
- endpoint: '/api/graphql',
1099
- headers: {
1100
- Authorization: 'Bearer your-token-here'
1101
- }
1102
- })
1103
-
1104
- // Use the generated methods with full type safety
1105
- const getUsersData = await client.GetUsers()
1106
- console.log(getUsersData.users) // Fully typed response
1107
-
1108
- const newUser = await client.CreateUser({
1109
- input: {
1110
- name: 'John Doe',
1111
- email: 'john@example.com'
1112
- }
1113
- })
1114
- console.log(newUser.createUser) // Fully typed response
1115
- ```
1116
-
1117
- </details>
1118
-
1119
- <details>
1120
- <summary>🎯 <strong>Basic Usage Examples</strong></summary>
1121
-
1122
- **Fetching Data:**
1123
- ```ts
1124
- // Import the generated client
1125
- import { createGraphQLClient } from '#graphql/client'
1126
-
1127
- const client = createGraphQLClient()
1128
-
1129
- // Query users
1130
- const { users } = await client.GetUsers()
1131
- console.log(users) // Array of User objects with full typing
1132
-
1133
- // Query specific user
1134
- const { user } = await client.GetUser({ id: '123' })
1135
- console.log(user) // User object or null
1136
- ```
1137
-
1138
- **Creating Data:**
1139
- ```ts
1140
- // Create a new user
1141
- const { createUser } = await client.CreateUser({
1142
- input: {
1143
- name: 'Jane Doe',
1144
- email: 'jane@example.com'
1145
- }
1146
- })
1147
- console.log(createUser) // Newly created user with full typing
1148
- ```
1149
-
1150
- **Error Handling:**
1151
- ```ts
1152
- try {
1153
- const { users } = await client.GetUsers()
1154
- console.log(users)
1155
- }
1156
- catch (error) {
1157
- console.error('GraphQL Error:', error)
1158
- // Handle GraphQL errors appropriately
1159
- }
1160
- ```
1161
-
1162
- </details>
1163
-
1164
- <details>
1165
- <summary>🔧 <strong>Client Configuration</strong></summary>
1166
-
1167
- ```ts
1168
- import { createGraphQLClient } from '#graphql/client'
1169
-
1170
- // Basic configuration
1171
- const client = createGraphQLClient({
1172
- endpoint: '/api/graphql',
1173
- headers: {
1174
- 'Authorization': 'Bearer your-token',
1175
- 'X-Client-Version': '1.0.0'
1176
- },
1177
- timeout: 10000
1178
- })
1179
-
1180
- // Advanced configuration with dynamic headers
1181
- const client = createGraphQLClient({
1182
- endpoint: '/api/graphql',
1183
- headers: async () => {
1184
- const token = await getAuthToken()
1185
- return {
1186
- 'Authorization': token ? `Bearer ${token}` : '',
1187
- 'X-Request-ID': crypto.randomUUID()
1188
- }
1189
- },
1190
- retry: 3,
1191
- timeout: 30000
1192
- })
1193
- ```
1194
-
1195
- </details>
1196
-
1197
- </details>
1198
-
1199
- ## 🛠️ Development
1200
-
1201
- ### Scripts
1202
-
1203
- - `pnpm build` - Build the module
1204
- - `pnpm dev` - Watch mode with automatic rebuilding
1205
- - `pnpm lint` - ESLint with auto-fix
1206
- - `pnpm playground` - Run the Nitro playground example
1207
- - `pnpm release` - Build, version bump, and publish
1208
-
1209
- ### Requirements
1210
-
1211
- - Node.js 20.x or later
1212
- - pnpm (required package manager)
1213
-
1214
- ## 💬 Community & Contributing
1215
-
1216
- > [!TIP]
1217
- > **Want to contribute?** We believe you can play a role in the growth of this project!
1218
-
1219
- ### 🎯 How You Can Contribute
1220
-
1221
- - **💡 Share your ideas**: Use [GitHub Issues](https://github.com/productdevbook/nitro-graphql/issues) for new feature suggestions
1222
- - **🐛 Report bugs**: Report issues you encounter in detail
1223
- - **📖 Improve documentation**: Enhance README, examples, and guides
1224
- - **🔧 Code contributions**: Develop bug fixes and new features
1225
- - **🌟 Support the project**: Support the project by giving it a star
1226
-
1227
- ### 💬 Discussion and Support
1228
-
1229
- - **GitHub Issues**: Feature requests and bug reports
1230
- - **GitHub Discussions**: General discussions and questions
1231
- - **Pull Requests**: Code contributions
1232
-
1233
- ### 🚀 Contribution Process
1234
-
1235
- 1. **Open an issue**: Let's discuss what you want to do first
1236
- 2. **Fork & Branch**: Fork the project and create a feature branch
1237
- 3. **Write code**: Develop according to existing code standards
1238
- 4. **Test**: Test your changes
1239
- 5. **Send PR**: Create a pull request with detailed description
1240
-
1241
- > [!IMPORTANT]
1242
- > Please don't forget to read the [Contribution Guidelines](CONTRIBUTING.md) document before contributing.
1243
-
1244
- ## 📋 Community TODOs
1245
-
1246
- Help us improve nitro-graphql! Pick any item and contribute:
1247
-
1248
- ### 🚀 Framework Examples
1249
- - [ ] Nitro-compatible framework integrations
1250
- - [ ] Nuxt + Pinia Colada example
1251
- - [ ] StackBlitz playground demos
1252
-
1253
- ### 🧹 Code Quality
1254
- - [ ] Performance benchmarks
1255
- - [ ] Bundle size optimization
1256
- - [ ] Testing utilities
1257
- - [ ] Error handling patterns
1258
-
1259
- ### 📚 Documentation
1260
- - [ ] Video tutorials
1261
- - [ ] Migration guides
1262
- - [ ] Best practices guide
1263
-
1264
- ### 🔧 Developer Tools
1265
- - [ ] VS Code extension
1266
- - [ ] CLI tools
1267
- - [ ] Debug utilities
1268
-
1269
- ### 🌐 Integrations
1270
- - [ ] Database adapters (Prisma, Drizzle)
1271
- - [ ] Cache strategies
1272
- - [ ] Deployment guides
1273
-
1274
- > [!NOTE]
1275
- > Have other ideas? Open an issue to discuss!
1276
-
1277
- ## 🔗 Multi-Service GraphQL Support
1278
-
1279
- Connect to multiple external GraphQL APIs alongside your main GraphQL server. Perfect for integrating with services like GitHub API, Shopify API, or any GraphQL endpoint.
1280
-
1281
- ### Configuration
1282
-
1283
- ```typescript
1284
- // nuxt.config.ts (for Nuxt projects)
1285
- export default defineNuxtConfig({
1286
- nitro: {
1287
- graphql: {
1288
- framework: 'graphql-yoga',
1289
- externalServices: [
1290
- {
1291
- name: 'countries',
1292
- schema: 'https://countries.trevorblades.com',
1293
- endpoint: 'https://countries.trevorblades.com',
1294
- documents: ['app/graphql/external/countries/**/*.graphql'],
1295
- headers: {
1296
- // Optional: Add custom headers
1297
- 'Authorization': 'Bearer your-token'
1298
- }
1299
- },
1300
- {
1301
- name: 'github',
1302
- schema: 'https://api.github.com/graphql',
1303
- endpoint: 'https://api.github.com/graphql',
1304
- documents: ['app/graphql/external/github/**/*.graphql'],
1305
- headers: () => ({
1306
- // Dynamic headers with function
1307
- 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
1308
- })
1309
- }
1310
- ]
1311
- }
1312
- }
1313
- })
1314
- ```
1315
-
1316
- ### Schema Download & Caching (Optional)
1317
-
1318
- For better performance and offline development, you can download and cache external schemas locally:
1319
-
1320
- ```typescript
1321
- // nuxt.config.ts
1322
- export default defineNuxtConfig({
1323
- nitro: {
1324
- graphql: {
1325
- framework: 'graphql-yoga',
1326
- externalServices: [
1327
- {
1328
- name: 'github',
1329
- schema: 'https://docs.github.com/public/schema.docs.graphql',
1330
- endpoint: 'https://api.github.com/graphql',
1331
- downloadSchema: 'once', // Download mode (see options below)
1332
- downloadPath: './schemas/github.graphql', // Optional: custom download path
1333
- headers: () => ({
1334
- 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
1335
- })
1336
- }
1337
- ]
1338
- }
1339
- }
1340
- })
1341
- ```
1342
-
1343
- **Download Modes:**
1344
-
1345
- | Mode | Behavior | Use Case |
1346
- |------|----------|----------|
1347
- | `true` or `'once'` | Download only if file doesn't exist | **Offline-friendly development** |
1348
- | `'always'` | Check for updates on every build | **Always stay up-to-date** |
1349
- | `'manual'` | Never download automatically | **Full manual control** |
1350
- | `false` | Disable schema downloading | **Always use remote** |
1351
-
1352
- **Benefits:**
1353
- - **Offline Development**: Work without internet connection after initial download
1354
- - **Faster Builds**: No remote fetching on each build when using 'once' mode
1355
- - **Version Control**: Commit downloaded schemas to track API changes
1356
- - **Network Reliability**: Fallback to cached schema if remote is unavailable
1357
-
1358
- **How it works:**
1359
- - **'once' mode (recommended)**: Downloads schema only if file doesn't exist, then uses cached version
1360
- - **'always' mode**: Checks for schema changes on every build using hash comparison
1361
- - **'manual' mode**: User manages schema files manually, no automatic downloading
1362
-
1363
- **File locations:**
1364
- - Default: `.nitro/graphql/schemas/[serviceName].graphql`
1365
- - Custom: Use `downloadPath` option to specify your preferred location
1366
-
1367
- ### Usage
1368
-
1369
- #### 1. Create External Service Queries
1370
-
1371
- ```graphql
1372
- <!-- app/graphql/external/countries/countries.graphql -->
1373
- query GetCountries {
1374
- countries {
1375
- code
1376
- name
1377
- emoji
1378
- continent {
1379
- name
1380
- }
1381
- }
1382
- }
1383
-
1384
- query GetCountry($code: ID!) {
1385
- country(code: $code) {
1386
- code
1387
- name
1388
- capital
1389
- currency
1390
- }
1391
- }
1392
- ```
1393
-
1394
- #### 2. Use Generated SDKs
1395
-
1396
- ```typescript
1397
- // Import from centralized index
1398
- import { $sdk, $countriesSdk, $githubSdk } from '~/app/graphql'
1399
-
1400
- // Or import directly from service folders
1401
- import { $countriesSdk } from '~/app/graphql/countries/ofetch'
1402
-
1403
- // Use in components
1404
- const countries = await $countriesSdk.GetCountries()
1405
- const country = await $countriesSdk.GetCountry({ code: 'US' })
1406
-
1407
- // Your main service still works
1408
- const users = await $sdk.GetUsers()
1409
- ```
1410
-
1411
- #### 3. Folder Structure
1412
-
1413
- After configuration, your project structure becomes:
1414
-
1415
- ```
1416
- app/graphql/
1417
- ├── index.ts # Centralized exports (auto-generated)
1418
- ├── default/ # Your main GraphQL service
1419
- │ ├── ofetch.ts # Main service client
1420
- │ └── sdk.ts # Main service SDK
1421
- ├── countries/ # External countries service
1422
- │ ├── ofetch.ts # Countries service client
1423
- │ └── sdk.ts # Countries service SDK
1424
- ├── github/ # External GitHub service
1425
- │ ├── ofetch.ts # GitHub service client
1426
- │ └── sdk.ts # GitHub service SDK
1427
- └── external/ # Your external service queries
1428
- ├── countries/
1429
- │ └── countries.graphql
1430
- └── github/
1431
- └── repositories.graphql
1432
- ```
1433
-
1434
- #### 4. TypeScript Support
1435
-
1436
- Each service gets its own type definitions:
1437
-
1438
- ```typescript
1439
- // Types are automatically generated and available
1440
- import type { GetCountriesQuery } from '#graphql/client/countries'
1441
- import type { GetUsersQuery } from '#graphql/client'
1442
-
1443
- const handleCountries = (countries: GetCountriesQuery) => {
1444
- // Fully typed countries data
1445
- }
1446
- ```
1447
-
1448
- ### Service Configuration Options
1449
-
1450
- | Option | Type | Required | Description |
1451
- |--------|------|----------|-------------|
1452
- | `name` | `string` | ✅ | Unique service name (used for folder/file names) |
1453
- | `schema` | `string` \| `string[]` | ✅ | GraphQL schema URL or file path |
1454
- | `endpoint` | `string` | ✅ | GraphQL endpoint URL for queries |
1455
- | `documents` | `string[]` | ❌ | Glob patterns for GraphQL query files |
1456
- | `headers` | `Record<string, string>` \| `() => Record<string, string>` | ❌ | Custom headers for schema introspection and queries |
1457
- | `codegen.client` | `CodegenClientConfig` | ❌ | Custom codegen configuration for client types |
1458
- | `codegen.clientSDK` | `GenericSdkConfig` | ❌ | Custom codegen configuration for SDK generation |
1459
-
1460
- ## 🛠️ GraphQL Config (Optional but Recommended)
1461
-
1462
- To enable GraphQL language features in your IDE (autocompletion, validation, go-to definition), create a `graphql.config.ts` file in your project root:
1463
-
1464
- ### For Single Service (Main GraphQL Server Only)
1465
-
1466
- ```typescript
1467
- // graphql.config.ts
1468
- import type { IGraphQLConfig } from 'graphql-config'
1469
-
1470
- export default <IGraphQLConfig> {
1471
- schema: ['./.nuxt/graphql/schema.graphql'],
1472
- documents: ['./app/graphql/**/*.{graphql,js,ts,jsx,tsx}'],
1473
- exclude: ['./app/graphql/external/**/*'] // Exclude external service documents
1474
- }
1475
- ```
1476
-
1477
- ### For Multi-Service Setup
1478
-
1479
- ```typescript
1480
- // graphql.config.ts
1481
- import type { IGraphQLConfig } from 'graphql-config'
1482
-
1483
- export default <IGraphQLConfig> {
1484
- projects: {
1485
- // Main GraphQL server
1486
- default: {
1487
- schema: ['./.nuxt/graphql/schema.graphql'],
1488
- documents: ['./app/graphql/default/**/*.{graphql,js,ts,jsx,tsx}']
1489
- },
1490
- // External services
1491
- github: {
1492
- schema: [
1493
- // Use downloaded schema if available, otherwise use remote
1494
- './.nuxt/graphql/schemas/github.graphql',
1495
- // Fallback to remote if local doesn't exist
1496
- 'https://docs.github.com/public/schema.docs.graphql'
1497
- ],
1498
- documents: ['./app/graphql/external/github/**/*.graphql']
1499
- },
1500
- countries: {
1501
- schema: ['./.nuxt/graphql/schemas/countries.graphql'],
1502
- documents: ['./app/graphql/external/countries/**/*.graphql']
1503
- }
1504
- }
1505
- }
1506
- ```
1507
-
1508
- ### Schema Paths for Different Download Modes
1509
-
1510
- - **Downloaded schemas**: `./.nuxt/graphql/schemas/[serviceName].graphql`
1511
- - **Custom download path**: Use your `downloadPath` configuration
1512
- - **Remote fallback**: Include remote URL as second option
1513
-
1514
- This configuration enables:
1515
- - 🎯 **Service-specific validation**: Each GraphQL service gets its own validation rules
1516
- - 🚀 **IDE autocompletion**: Full IntelliSense for queries and mutations
1517
- - ✅ **Real-time validation**: Catch GraphQL errors while typing
1518
- - 🔍 **Go-to definition**: Navigate to type definitions across services
1519
-
1520
- ## 🛠️ VS Code Extensions
1521
-
1522
- For the best development experience with GraphQL, install these recommended VS Code extensions:
1523
-
1524
- - **[GraphQL: Language Feature Support](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql)** - Provides GraphQL language features like autocompletion, go-to definition, and schema validation
1525
- - **[GraphQL: Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql-syntax)** - Adds syntax highlighting for GraphQL queries, mutations, subscriptions, and schema files
1526
-
1527
- These extensions will enable:
1528
- - 🎨 Syntax highlighting for `.graphql` files
1529
- - 📝 IntelliSense and autocompletion based on your schema
1530
- - ✅ Real-time validation of GraphQL queries
1531
- - 🔍 Go-to definition for types and fields
1532
- - 💡 Hover information for GraphQL elements
1533
-
1534
- ---
1535
-
1536
- ### 🌟 Thank You
1537
-
1538
- Thank you for using and developing this project. Every contribution makes the GraphQL ecosystem stronger!
1539
-
1540
- ## Sponsors
1541
-
1542
- <p align="center">
1543
- <a href="https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg">
1544
- <img src='https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg?t=1721043966'/>
1545
- </a>
1546
- </p>
1547
-
1548
- ## License
415
+ ## License
1549
416
 
1550
417
  [MIT](./LICENSE) License © 2023 [productdevbook](https://github.com/productdevbook)
1551
418
 
1552
419
  <!-- Badges -->
1553
-
1554
420
  [npm-version-src]: https://img.shields.io/npm/v/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
1555
421
  [npm-version-href]: https://npmjs.com/package/nitro-graphql
1556
422
  [npm-downloads-src]: https://img.shields.io/npm/dm/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
@@ -1558,5 +424,4 @@ Thank you for using and developing this project. Every contribution makes the Gr
1558
424
  [bundle-src]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1559
425
  [bundle-href]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1560
426
  [license-src]: https://img.shields.io/github/license/productdevbook/nitro-graphql.svg?style=flat&colorA=080f12&colorB=1fa669
1561
- [license-href]: https://github.com/productdevbook/nitro-graphql/blob/main/LICENSE
1562
- [jsdocs-href]: https://www.jsdocs.io/package/nitro-graphql
427
+ [license-href]: https://github.com/productdevbook/nitro-graphql/blob/main/LICENSE