nitro-graphql 1.4.0 → 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,1126 +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**: [`playgrounds/nitro/`](playgrounds/nitro/)
465
- - **Nuxt.js Integration**: [`playgrounds/nuxt/`](playgrounds/nuxt/)
466
- - **Apollo Federation**: [`playgrounds/federation/`](playgrounds/federation/)
467
-
468
- All examples include working GraphQL schemas, resolvers, and demonstrate the module's capabilities.
469
-
470
- ## 🔧 API Reference
290
+ ## 📖 Documentation
471
291
 
472
292
  ### Core Utilities
473
293
 
474
- > [!NOTE]
475
- > **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:
476
- > ```ts
477
- > import { defineMutation, defineQuery, defineResolver } from 'nitro-graphql/utils/define'
478
- > ```
294
+ All utilities are auto-imported in resolver files:
479
295
 
480
- > [!IMPORTANT]
481
- > **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:
482
- > ```ts
483
- > // Correct - Named exports
484
- > export const userQueries = defineQuery({ ... })
485
- > export const userMutations = defineMutation({ ... })
486
- >
487
- > // ❌ Incorrect - Default exports (deprecated)
488
- > export default defineQuery({ ... })
489
- > ```
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', ... })` |
490
303
 
491
- <details>
492
- <summary><strong>defineResolver</strong> - Define complete resolvers</summary>
304
+ ### Type Generation
493
305
 
494
- ```ts
495
- 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
496
309
 
497
- export const mainResolver = defineResolver({
498
- Query: {
499
- // Query resolvers
500
- },
501
- Mutation: {
502
- // Mutation resolvers
503
- },
504
- // Custom type resolvers
505
- })
310
+ ```ts
311
+ // Server-side
312
+ import type { User, CreateUserInput } from '#graphql/server'
506
313
 
507
- // You can also export multiple resolvers from the same file
508
- export const additionalResolver = defineResolver({
509
- Query: {
510
- // Additional query resolvers
511
- },
512
- })
314
+ // Client-side
315
+ import type { GetUsersQuery, CreateUserMutation } from '#graphql/client'
513
316
  ```
514
317
 
515
- </details>
516
-
517
- <details>
518
- <summary><strong>defineQuery</strong> - Define only Query resolvers</summary>
519
-
520
- ```ts
521
- import { defineQuery } from 'nitro-graphql/utils/define'
522
-
523
- export const userQueries = defineQuery({
524
- users: async (_, __, { storage }) => {
525
- return await storage.getItem('users') || []
526
- },
527
- user: async (_, { id }, { storage }) => {
528
- const users = await storage.getItem('users') || []
529
- return users.find(user => user.id === id)
530
- }
531
- })
318
+ ### Project Structure
532
319
 
533
- // You can also split queries into separate named exports
534
- export const userStatsQueries = defineQuery({
535
- userCount: async (_, __, { storage }) => {
536
- const users = await storage.getItem('users') || []
537
- return users.length
538
- },
539
- })
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
540
330
  ```
541
331
 
542
- </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
+ > ```
543
340
 
544
- <details>
545
- <summary><strong>defineMutation</strong> - Define only Mutation resolvers</summary>
341
+ ## 🚨 Troubleshooting
546
342
 
547
- ```ts
548
- import { defineMutation } from 'nitro-graphql/utils/define'
343
+ <details>
344
+ <summary><strong>Common Issues</strong></summary>
549
345
 
550
- export const userMutations = defineMutation({
551
- createUser: async (_, { input }, { storage }) => {
552
- const users = await storage.getItem('users') || []
553
- const user = {
554
- id: Date.now().toString(),
555
- ...input,
556
- createdAt: new Date()
557
- }
558
- users.push(user)
559
- await storage.setItem('users', users)
560
- return user
561
- }
562
- })
346
+ **GraphQL endpoint returns 404**
347
+ - Check `nitro-graphql` is in modules
348
+ - Set `graphql.framework` option
349
+ - Create at least one `.graphql` file
563
350
 
564
- // You can also export multiple mutations from the same file
565
- export const userUpdateMutations = defineMutation({
566
- updateUser: async (_, { id, input }, { storage }) => {
567
- const users = await storage.getItem('users') || []
568
- const userIndex = users.findIndex(user => user.id === id)
569
- if (userIndex === -1)
570
- 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
571
355
 
572
- users[userIndex] = { ...users[userIndex], ...input }
573
- await storage.setItem('users', users)
574
- return users[userIndex]
575
- }
576
- })
577
- ```
356
+ **Import errors**
357
+ - Use correct path: `nitro-graphql/utils/define`
358
+ - ✅ Use named exports in resolvers
578
359
 
579
360
  </details>
580
361
 
581
- <details>
582
- <summary><strong>defineSubscription</strong> - Define Subscription resolvers</summary>
362
+ ## 🌟 Production Usage
583
363
 
584
- ```ts
585
- import { defineSubscription } from 'nitro-graphql/utils/define'
364
+ This package powers production applications:
586
365
 
587
- export const userSubscriptions = defineSubscription({
588
- userAdded: {
589
- subscribe: () => pubsub.asyncIterator('USER_ADDED'),
590
- },
591
- postUpdated: {
592
- subscribe: withFilter(
593
- () => pubsub.asyncIterator('POST_UPDATED'),
594
- (payload, variables) => payload.postUpdated.id === variables.postId
595
- ),
596
- }
597
- })
366
+ - [**Nitroping**](https://github.com/productdevbook/nitroping) - Self-hosted push notification service
598
367
 
599
- // You can also export multiple subscriptions from the same file
600
- export const notificationSubscriptions = defineSubscription({
601
- notificationAdded: {
602
- subscribe: () => pubsub.asyncIterator('NOTIFICATION_ADDED'),
603
- },
604
- })
605
- ```
368
+ ## 🛠️ Development
606
369
 
607
- </details>
370
+ ```bash
371
+ # Install dependencies
372
+ pnpm install
608
373
 
609
- <details>
610
- <summary><strong>defineType</strong> - Define custom type resolvers</summary>
374
+ # Build module
375
+ pnpm build
611
376
 
612
- ```ts
613
- import { defineType } from 'nitro-graphql/utils/define'
377
+ # Watch mode
378
+ pnpm dev
614
379
 
615
- export const userTypes = defineType({
616
- User: {
617
- posts: async (parent, _, { storage }) => {
618
- const posts = await storage.getItem('posts') || []
619
- return posts.filter(post => post.authorId === parent.id)
620
- },
621
- fullName: parent => `${parent.firstName} ${parent.lastName}`,
622
- },
623
- })
380
+ # Run playgrounds
381
+ pnpm playground:nitro
382
+ pnpm playground:nuxt
383
+ pnpm playground:federation
624
384
 
625
- // You can also export multiple type resolvers from the same file
626
- export const postTypes = defineType({
627
- Post: {
628
- author: async (parent, _, { storage }) => {
629
- const users = await storage.getItem('users') || []
630
- return users.find(user => user.id === parent.authorId)
631
- },
632
- },
633
- })
385
+ # Lint
386
+ pnpm lint
634
387
  ```
635
388
 
636
- </details>
389
+ ## 💬 Community
637
390
 
638
- <details>
639
- <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!
640
393
 
641
- ```ts
642
- import { defineDirective } from 'nitro-graphql/utils/define'
643
- import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
644
- 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
645
400
 
646
- export const authDirective = defineDirective({
647
- name: 'auth',
648
- locations: ['FIELD_DEFINITION', 'OBJECT'],
649
- args: {
650
- requires: {
651
- type: 'String',
652
- defaultValue: 'USER',
653
- description: 'Required role to access this field',
654
- },
655
- },
656
- description: 'Directive to check authentication and authorization',
657
- transformer: (schema) => {
658
- return mapSchema(schema, {
659
- [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
660
- const authDirectiveConfig = getDirective(schema, fieldConfig, 'auth')?.[0]
661
-
662
- if (authDirectiveConfig) {
663
- const { resolve = defaultFieldResolver } = fieldConfig
664
-
665
- fieldConfig.resolve = async function (source, args, context, info) {
666
- if (!context.user) {
667
- throw new GraphQLError('You must be logged in')
668
- }
669
-
670
- if (context.user.role !== authDirectiveConfig.requires) {
671
- throw new GraphQLError('Insufficient permissions')
672
- }
673
-
674
- return resolve(source, args, context, info)
675
- }
676
- }
677
-
678
- return fieldConfig
679
- },
680
- })
681
- },
682
- })
683
- ```
401
+ ### Help Wanted
402
+ - [ ] Performance benchmarks
403
+ - [ ] Video tutorials
404
+ - [ ] Database adapter guides
405
+ - [ ] VS Code extension
684
406
 
685
- **Usage in Schema:**
686
- ```graphql
687
- type User {
688
- id: ID!
689
- name: String!
690
- email: String! @auth(requires: "ADMIN")
691
- secretData: String @auth(requires: "SUPER_ADMIN")
692
- }
407
+ ## Sponsors
693
408
 
694
- type Query {
695
- users: [User!]! @auth
696
- adminStats: AdminStats @auth(requires: "ADMIN")
697
- }
698
- ```
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>
699
414
 
700
- **Available Argument Types:**
701
- - Basic scalars: `String`, `Int`, `Float`, `Boolean`, `ID`, `JSON`, `DateTime`
702
- - Non-nullable: `String!`, `Int!`, `Float!`, `Boolean!`, `ID!`, `JSON!`, `DateTime!`
703
- - Arrays: `[String]`, `[String!]`, `[String]!`, `[String!]!` (and all combinations for other types)
704
- - Custom types: Any string for your custom GraphQL types
705
-
706
- **Helper Function:**
707
- ```ts
708
- export const validateDirective = defineDirective({
709
- name: 'validate',
710
- locations: ['FIELD_DEFINITION', 'ARGUMENT_DEFINITION'],
711
- args: {
712
- minLength: arg('Int', { description: 'Minimum length' }),
713
- maxLength: arg('Int', { description: 'Maximum length' }),
714
- pattern: arg('String', { description: 'Regex pattern' }),
715
- },
716
- // ... transformer implementation
717
- })
718
- ```
719
-
720
- </details>
721
-
722
- <details>
723
- <summary><strong>defineSchema</strong> - Define custom schema with validation</summary>
724
-
725
- You can override schema types if needed. StandardSchema supported — Zod, Valibot, anything works:
726
-
727
- ```ts
728
- # server/graphql/schema.ts
729
- import { defineSchema } from 'nitro-graphql/utils/define'
730
- import { z } from 'zod'
731
-
732
- export default defineSchema({
733
- Todo: z.object({
734
- id: z.string(),
735
- title: z.string(),
736
- completed: z.boolean(),
737
- createdAt: z.date(),
738
- }),
739
- User: z.object({
740
- id: z.string(),
741
- name: z.string(),
742
- email: z.string().email(),
743
- age: z.number().min(0),
744
- }),
745
- })
746
- ```
747
-
748
- **With Drizzle Schema:**
749
- ```ts
750
- import { defineSchema } from 'nitro-graphql/utils/define'
751
- import { z } from 'zod'
752
- import { userSchema } from './drizzle/user'
753
-
754
- export default defineSchema({
755
- Todo: z.object({
756
- id: z.string(),
757
- title: z.string(),
758
- }),
759
- User: userSchema, // Import from Drizzle schema
760
- })
761
- ```
762
-
763
- </details>
764
-
765
- ## 🚨 Troubleshooting
766
-
767
- <details>
768
- <summary><strong>Common Issues</strong></summary>
769
-
770
- ### GraphQL endpoint returns 404
771
-
772
- **Solution**: Make sure you have:
773
- 1. Added `nitro-graphql` to your modules
774
- 2. Set the `graphql.framework` option
775
- 3. Created at least one schema file
776
-
777
- ### Types not generating
778
-
779
- **Solution**:
780
- 1. Restart your dev server
781
- 2. Check that your schema files end with `.graphql`
782
- 3. Verify your resolver files end with `.resolver.ts`
783
-
784
- ### Hot reload not working
785
-
786
- **Solution**:
787
- 1. Make sure you're in development mode
788
- 2. Check file naming conventions
789
- 3. Restart the dev server
790
-
791
- ### Import errors with utilities
792
-
793
- **Solution**:
794
- ```ts
795
- // ❌ Incorrect import path
796
- import { defineResolver } from 'nitro-graphql'
797
-
798
- // ✅ Correct import path
799
- import { defineResolver } from 'nitro-graphql/utils/define'
800
- ```
801
-
802
- ### Export pattern errors
803
-
804
- **Solution**:
805
- ```ts
806
- // ❌ Incorrect - Default exports (deprecated)
807
- export default defineResolver({ ... })
808
-
809
- // ✅ Correct - Named exports
810
- export const myResolver = defineResolver({ ... })
811
- export const anotherResolver = defineResolver({ ... })
812
- ```
813
-
814
- </details>
815
-
816
- ## 🌟 Framework Support
817
-
818
- <details>
819
- <summary><strong>GraphQL Yoga</strong></summary>
820
-
821
- ```ts
822
- // nitro.config.ts
823
- export default defineNitroConfig({
824
- graphql: {
825
- framework: 'graphql-yoga',
826
- },
827
- })
828
- ```
829
-
830
- </details>
831
-
832
- <details>
833
- <summary><strong>Apollo Server</strong></summary>
834
-
835
- ```ts
836
- // nitro.config.ts
837
- export default defineNitroConfig({
838
- graphql: {
839
- framework: 'apollo-server',
840
- },
841
- })
842
- ```
843
-
844
- </details>
845
-
846
- ## 🔥 Advanced Features
847
-
848
- <details>
849
- <summary><strong>Custom Directives</strong></summary>
850
-
851
- Create reusable GraphQL directives with automatic schema generation:
852
-
853
- ```ts
854
- // server/graphql/directives/auth.directive.ts
855
- import { defineDirective } from 'nitro-graphql/utils/define'
856
- import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
857
-
858
- export const authDirective = defineDirective({
859
- name: 'auth',
860
- locations: ['FIELD_DEFINITION', 'OBJECT'],
861
- args: {
862
- requires: {
863
- type: 'String',
864
- defaultValue: 'USER',
865
- description: 'Required role to access this field',
866
- },
867
- },
868
- description: 'Authentication and authorization directive',
869
- transformer: (schema) => {
870
- return mapSchema(schema, {
871
- [MapperKind.OBJECT_FIELD]: (fieldConfig) => {
872
- const authConfig = getDirective(schema, fieldConfig, 'auth')?.[0]
873
- if (authConfig) {
874
- // Transform field resolvers to check authentication
875
- const { resolve = defaultFieldResolver } = fieldConfig
876
- fieldConfig.resolve = async (source, args, context, info) => {
877
- if (!context.user || context.user.role !== authConfig.requires) {
878
- throw new GraphQLError('Access denied')
879
- }
880
- return resolve(source, args, context, info)
881
- }
882
- }
883
- return fieldConfig
884
- },
885
- })
886
- },
887
- })
888
- ```
889
-
890
- **Common Directive Examples:**
891
- - `@auth(requires: "ADMIN")` - Role-based authentication
892
- - `@cache(ttl: 300, scope: "PUBLIC")` - Field-level caching
893
- - `@rateLimit(limit: 10, window: 60)` - Rate limiting
894
- - `@validate(minLength: 5, maxLength: 100)` - Input validation
895
- - `@transform(upper: true, trim: true)` - Data transformation
896
- - `@permission(roles: ["ADMIN", "MODERATOR"])` - Multi-role permissions
897
-
898
- **Usage in Schema:**
899
- ```graphql
900
- type User {
901
- id: ID!
902
- name: String!
903
- email: String! @auth(requires: "ADMIN")
904
- posts: [Post!]! @cache(ttl: 300)
905
- }
906
-
907
- type Query {
908
- users: [User!]! @rateLimit(limit: 100, window: 3600)
909
- sensitiveData: String @auth(requires: "SUPER_ADMIN")
910
- }
911
- ```
912
-
913
- The module automatically generates the directive schema definitions and integrates them with both GraphQL Yoga and Apollo Server.
914
-
915
- </details>
916
-
917
- <details>
918
- <summary><strong>Custom Scalars</strong></summary>
919
-
920
- ```ts
921
- // server/graphql/scalars/DateTime.resolver.ts
922
- import { GraphQLScalarType } from 'graphql'
923
- import { Kind } from 'graphql/language'
924
- import { defineResolver } from 'nitro-graphql/utils/define'
925
-
926
- export const dateTimeScalar = defineResolver({
927
- DateTime: new GraphQLScalarType({
928
- name: 'DateTime',
929
- serialize: (value: Date) => value.toISOString(),
930
- parseValue: (value: string) => new Date(value),
931
- parseLiteral: (ast) => {
932
- if (ast.kind === Kind.STRING) {
933
- return new Date(ast.value)
934
- }
935
- return null
936
- }
937
- })
938
- })
939
-
940
- // You can also export multiple scalars from the same file
941
- export const jsonScalar = defineResolver({
942
- JSON: new GraphQLScalarType({
943
- name: 'JSON',
944
- serialize: value => value,
945
- parseValue: value => value,
946
- parseLiteral: (ast) => {
947
- if (ast.kind === Kind.STRING) {
948
- return JSON.parse(ast.value)
949
- }
950
- return null
951
- }
952
- })
953
- })
954
- ```
955
-
956
- </details>
957
-
958
- <details>
959
- <summary><strong>Error Handling</strong></summary>
960
-
961
- ```ts
962
- // server/graphql/users/user-queries.resolver.ts
963
- import { defineQuery } from 'nitro-graphql/utils/define'
964
-
965
- export const userQueries = defineQuery({
966
- user: async (_, { id }, { storage }) => {
967
- try {
968
- const user = await storage.getItem(`user:${id}`)
969
- if (!user) {
970
- throw new Error(`User with id ${id} not found`)
971
- }
972
- return user
973
- }
974
- catch (error) {
975
- console.error('Error fetching user:', error)
976
- throw error
977
- }
978
- }
979
- })
980
-
981
- // You can also export additional error handling queries
982
- export const safeUserQueries = defineQuery({
983
- userSafe: async (_, { id }, { storage }) => {
984
- try {
985
- const user = await storage.getItem(`user:${id}`)
986
- return user || null // Return null instead of throwing
987
- }
988
- catch (error) {
989
- console.error('Error fetching user:', error)
990
- return null
991
- }
992
- }
993
- })
994
- ```
995
-
996
- </details>
997
-
998
- <details>
999
- <summary><strong>Nuxt Integration</strong></summary>
1000
-
1001
- For Nuxt.js applications, the module provides enhanced integration:
1002
-
1003
- ```ts
1004
- // nuxt.config.ts
1005
- export default defineNuxtConfig({
1006
- modules: [
1007
- 'nitro-graphql/nuxt',
1008
- ],
1009
- nitro: {
1010
- modules: ['nitro-graphql'],
1011
- graphql: {
1012
- framework: 'graphql-yoga',
1013
- },
1014
- },
1015
- })
1016
- ```
1017
-
1018
- Client-side GraphQL files are automatically detected in the `app/graphql/` directory.
1019
-
1020
- ### Client-Side Usage
1021
-
1022
- The module automatically generates a GraphQL SDK and provides type-safe client access for frontend usage.
1023
-
1024
- <details>
1025
- <summary>📁 <strong>GraphQL File Structure</strong></summary>
1026
-
1027
- Create your GraphQL queries and mutations in the `app/graphql/` directory:
1028
-
1029
- ```
1030
- app/
1031
- ├── graphql/
1032
- │ ├── queries.graphql # GraphQL queries
1033
- │ ├── mutations.graphql # GraphQL mutations
1034
- │ └── subscriptions.graphql # GraphQL subscriptions (optional)
1035
- ```
1036
-
1037
- </details>
1038
-
1039
- <details>
1040
- <summary>🔥 <strong>Creating GraphQL Files</strong></summary>
1041
-
1042
- **Query File Example:**
1043
- ```graphql
1044
- # app/graphql/queries.graphql
1045
- query GetUsers {
1046
- users {
1047
- id
1048
- name
1049
- email
1050
- createdAt
1051
- }
1052
- }
1053
-
1054
- query GetUser($id: ID!) {
1055
- user(id: $id) {
1056
- id
1057
- name
1058
- email
1059
- createdAt
1060
- }
1061
- }
1062
- ```
1063
-
1064
- **Mutation File Example:**
1065
- ```graphql
1066
- # app/graphql/mutations.graphql
1067
- mutation CreateUser($input: CreateUserInput!) {
1068
- createUser(input: $input) {
1069
- id
1070
- name
1071
- email
1072
- createdAt
1073
- }
1074
- }
1075
-
1076
- mutation UpdateUser($id: ID!, $input: UpdateUserInput!) {
1077
- updateUser(id: $id, input: $input) {
1078
- id
1079
- name
1080
- email
1081
- createdAt
1082
- }
1083
- }
1084
- ```
1085
-
1086
- </details>
1087
-
1088
- <details>
1089
- <summary>⚡ <strong>Using the Generated SDK</strong></summary>
1090
-
1091
- The module automatically generates a type-safe SDK based on your GraphQL files:
1092
-
1093
- ```ts
1094
- // The SDK is automatically generated and available as an import
1095
- import { createGraphQLClient } from '#graphql/client'
1096
-
1097
- // Create a client instance
1098
- const client = createGraphQLClient({
1099
- endpoint: '/api/graphql',
1100
- headers: {
1101
- Authorization: 'Bearer your-token-here'
1102
- }
1103
- })
1104
-
1105
- // Use the generated methods with full type safety
1106
- const getUsersData = await client.GetUsers()
1107
- console.log(getUsersData.users) // Fully typed response
1108
-
1109
- const newUser = await client.CreateUser({
1110
- input: {
1111
- name: 'John Doe',
1112
- email: 'john@example.com'
1113
- }
1114
- })
1115
- console.log(newUser.createUser) // Fully typed response
1116
- ```
1117
-
1118
- </details>
1119
-
1120
- <details>
1121
- <summary>🎯 <strong>Basic Usage Examples</strong></summary>
1122
-
1123
- **Fetching Data:**
1124
- ```ts
1125
- // Import the generated client
1126
- import { createGraphQLClient } from '#graphql/client'
1127
-
1128
- const client = createGraphQLClient()
1129
-
1130
- // Query users
1131
- const { users } = await client.GetUsers()
1132
- console.log(users) // Array of User objects with full typing
1133
-
1134
- // Query specific user
1135
- const { user } = await client.GetUser({ id: '123' })
1136
- console.log(user) // User object or null
1137
- ```
1138
-
1139
- **Creating Data:**
1140
- ```ts
1141
- // Create a new user
1142
- const { createUser } = await client.CreateUser({
1143
- input: {
1144
- name: 'Jane Doe',
1145
- email: 'jane@example.com'
1146
- }
1147
- })
1148
- console.log(createUser) // Newly created user with full typing
1149
- ```
1150
-
1151
- **Error Handling:**
1152
- ```ts
1153
- try {
1154
- const { users } = await client.GetUsers()
1155
- console.log(users)
1156
- }
1157
- catch (error) {
1158
- console.error('GraphQL Error:', error)
1159
- // Handle GraphQL errors appropriately
1160
- }
1161
- ```
1162
-
1163
- </details>
1164
-
1165
- <details>
1166
- <summary>🔧 <strong>Client Configuration</strong></summary>
1167
-
1168
- ```ts
1169
- import { createGraphQLClient } from '#graphql/client'
1170
-
1171
- // Basic configuration
1172
- const client = createGraphQLClient({
1173
- endpoint: '/api/graphql',
1174
- headers: {
1175
- 'Authorization': 'Bearer your-token',
1176
- 'X-Client-Version': '1.0.0'
1177
- },
1178
- timeout: 10000
1179
- })
1180
-
1181
- // Advanced configuration with dynamic headers
1182
- const client = createGraphQLClient({
1183
- endpoint: '/api/graphql',
1184
- headers: async () => {
1185
- const token = await getAuthToken()
1186
- return {
1187
- 'Authorization': token ? `Bearer ${token}` : '',
1188
- 'X-Request-ID': crypto.randomUUID()
1189
- }
1190
- },
1191
- retry: 3,
1192
- timeout: 30000
1193
- })
1194
- ```
1195
-
1196
- </details>
1197
-
1198
- </details>
1199
-
1200
- ## 🛠️ Development
1201
-
1202
- ### Scripts
1203
-
1204
- - `pnpm build` - Build the module
1205
- - `pnpm dev` - Watch mode with automatic rebuilding
1206
- - `pnpm lint` - ESLint with auto-fix
1207
- - `pnpm playground:nitro` - Run the Nitro playground example
1208
- - `pnpm playground:nuxt` - Run the Nuxt playground example
1209
- - `pnpm playground:federation` - Run the Apollo Federation playground
1210
- - `pnpm release` - Build, version bump, and publish
1211
-
1212
- ### Requirements
1213
-
1214
- - Node.js 20.x or later
1215
- - pnpm (required package manager)
1216
-
1217
- ## 💬 Community & Contributing
1218
-
1219
- > [!TIP]
1220
- > **Want to contribute?** We believe you can play a role in the growth of this project!
1221
-
1222
- ### 🎯 How You Can Contribute
1223
-
1224
- - **💡 Share your ideas**: Use [GitHub Issues](https://github.com/productdevbook/nitro-graphql/issues) for new feature suggestions
1225
- - **🐛 Report bugs**: Report issues you encounter in detail
1226
- - **📖 Improve documentation**: Enhance README, examples, and guides
1227
- - **🔧 Code contributions**: Develop bug fixes and new features
1228
- - **🌟 Support the project**: Support the project by giving it a star
1229
-
1230
- ### 💬 Discussion and Support
1231
-
1232
- - **GitHub Issues**: Feature requests and bug reports
1233
- - **GitHub Discussions**: General discussions and questions
1234
- - **Pull Requests**: Code contributions
1235
-
1236
- ### 🚀 Contribution Process
1237
-
1238
- 1. **Open an issue**: Let's discuss what you want to do first
1239
- 2. **Fork & Branch**: Fork the project and create a feature branch
1240
- 3. **Write code**: Develop according to existing code standards
1241
- 4. **Test**: Test your changes
1242
- 5. **Send PR**: Create a pull request with detailed description
1243
-
1244
- > [!IMPORTANT]
1245
- > Please don't forget to read the [Contribution Guidelines](CONTRIBUTING.md) document before contributing.
1246
-
1247
- ## 📋 Community TODOs
1248
-
1249
- Help us improve nitro-graphql! Pick any item and contribute:
1250
-
1251
- ### 🚀 Framework Examples
1252
- - [ ] Nitro-compatible framework integrations
1253
- - [ ] Nuxt + Pinia Colada example
1254
- - [ ] StackBlitz playground demos
1255
-
1256
- ### 🧹 Code Quality
1257
- - [ ] Performance benchmarks
1258
- - [ ] Bundle size optimization
1259
- - [ ] Testing utilities
1260
- - [ ] Error handling patterns
1261
-
1262
- ### 📚 Documentation
1263
- - [ ] Video tutorials
1264
- - [ ] Migration guides
1265
- - [ ] Best practices guide
1266
-
1267
- ### 🔧 Developer Tools
1268
- - [ ] VS Code extension
1269
- - [ ] CLI tools
1270
- - [ ] Debug utilities
1271
-
1272
- ### 🌐 Integrations
1273
- - [ ] Database adapters (Prisma, Drizzle)
1274
- - [ ] Cache strategies
1275
- - [ ] Deployment guides
1276
-
1277
- > [!NOTE]
1278
- > Have other ideas? Open an issue to discuss!
1279
-
1280
- ## 🔗 Multi-Service GraphQL Support
1281
-
1282
- 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.
1283
-
1284
- ### Configuration
1285
-
1286
- ```typescript
1287
- // nuxt.config.ts (for Nuxt projects)
1288
- export default defineNuxtConfig({
1289
- nitro: {
1290
- graphql: {
1291
- framework: 'graphql-yoga',
1292
- externalServices: [
1293
- {
1294
- name: 'countries',
1295
- schema: 'https://countries.trevorblades.com',
1296
- endpoint: 'https://countries.trevorblades.com',
1297
- documents: ['app/graphql/external/countries/**/*.graphql'],
1298
- headers: {
1299
- // Optional: Add custom headers
1300
- 'Authorization': 'Bearer your-token'
1301
- }
1302
- },
1303
- {
1304
- name: 'github',
1305
- schema: 'https://api.github.com/graphql',
1306
- endpoint: 'https://api.github.com/graphql',
1307
- documents: ['app/graphql/external/github/**/*.graphql'],
1308
- headers: () => ({
1309
- // Dynamic headers with function
1310
- 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
1311
- })
1312
- }
1313
- ]
1314
- }
1315
- }
1316
- })
1317
- ```
1318
-
1319
- ### Schema Download & Caching (Optional)
1320
-
1321
- For better performance and offline development, you can download and cache external schemas locally:
1322
-
1323
- ```typescript
1324
- // nuxt.config.ts
1325
- export default defineNuxtConfig({
1326
- nitro: {
1327
- graphql: {
1328
- framework: 'graphql-yoga',
1329
- externalServices: [
1330
- {
1331
- name: 'github',
1332
- schema: 'https://docs.github.com/public/schema.docs.graphql',
1333
- endpoint: 'https://api.github.com/graphql',
1334
- downloadSchema: 'once', // Download mode (see options below)
1335
- downloadPath: './schemas/github.graphql', // Optional: custom download path
1336
- headers: () => ({
1337
- 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
1338
- })
1339
- }
1340
- ]
1341
- }
1342
- }
1343
- })
1344
- ```
1345
-
1346
- **Download Modes:**
1347
-
1348
- | Mode | Behavior | Use Case |
1349
- |------|----------|----------|
1350
- | `true` or `'once'` | Download only if file doesn't exist | **Offline-friendly development** |
1351
- | `'always'` | Check for updates on every build | **Always stay up-to-date** |
1352
- | `'manual'` | Never download automatically | **Full manual control** |
1353
- | `false` | Disable schema downloading | **Always use remote** |
1354
-
1355
- **Benefits:**
1356
- - **Offline Development**: Work without internet connection after initial download
1357
- - **Faster Builds**: No remote fetching on each build when using 'once' mode
1358
- - **Version Control**: Commit downloaded schemas to track API changes
1359
- - **Network Reliability**: Fallback to cached schema if remote is unavailable
1360
-
1361
- **How it works:**
1362
- - **'once' mode (recommended)**: Downloads schema only if file doesn't exist, then uses cached version
1363
- - **'always' mode**: Checks for schema changes on every build using hash comparison
1364
- - **'manual' mode**: User manages schema files manually, no automatic downloading
1365
-
1366
- **File locations:**
1367
- - Default: `.nitro/graphql/schemas/[serviceName].graphql`
1368
- - Custom: Use `downloadPath` option to specify your preferred location
1369
-
1370
- ### Usage
1371
-
1372
- #### 1. Create External Service Queries
1373
-
1374
- ```graphql
1375
- <!-- app/graphql/external/countries/countries.graphql -->
1376
- query GetCountries {
1377
- countries {
1378
- code
1379
- name
1380
- emoji
1381
- continent {
1382
- name
1383
- }
1384
- }
1385
- }
1386
-
1387
- query GetCountry($code: ID!) {
1388
- country(code: $code) {
1389
- code
1390
- name
1391
- capital
1392
- currency
1393
- }
1394
- }
1395
- ```
1396
-
1397
- #### 2. Use Generated SDKs
1398
-
1399
- ```typescript
1400
- // Import from centralized index
1401
- import { $sdk, $countriesSdk, $githubSdk } from '~/app/graphql'
1402
-
1403
- // Or import directly from service folders
1404
- import { $countriesSdk } from '~/app/graphql/countries/ofetch'
1405
-
1406
- // Use in components
1407
- const countries = await $countriesSdk.GetCountries()
1408
- const country = await $countriesSdk.GetCountry({ code: 'US' })
1409
-
1410
- // Your main service still works
1411
- const users = await $sdk.GetUsers()
1412
- ```
1413
-
1414
- #### 3. Folder Structure
1415
-
1416
- After configuration, your project structure becomes:
1417
-
1418
- ```
1419
- app/graphql/
1420
- ├── index.ts # Centralized exports (auto-generated)
1421
- ├── default/ # Your main GraphQL service
1422
- │ ├── ofetch.ts # Main service client
1423
- │ └── sdk.ts # Main service SDK
1424
- ├── countries/ # External countries service
1425
- │ ├── ofetch.ts # Countries service client
1426
- │ └── sdk.ts # Countries service SDK
1427
- ├── github/ # External GitHub service
1428
- │ ├── ofetch.ts # GitHub service client
1429
- │ └── sdk.ts # GitHub service SDK
1430
- └── external/ # Your external service queries
1431
- ├── countries/
1432
- │ └── countries.graphql
1433
- └── github/
1434
- └── repositories.graphql
1435
- ```
1436
-
1437
- #### 4. TypeScript Support
1438
-
1439
- Each service gets its own type definitions:
1440
-
1441
- ```typescript
1442
- // Types are automatically generated and available
1443
- import type { GetCountriesQuery } from '#graphql/client/countries'
1444
- import type { GetUsersQuery } from '#graphql/client'
1445
-
1446
- const handleCountries = (countries: GetCountriesQuery) => {
1447
- // Fully typed countries data
1448
- }
1449
- ```
1450
-
1451
- ### Service Configuration Options
1452
-
1453
- | Option | Type | Required | Description |
1454
- |--------|------|----------|-------------|
1455
- | `name` | `string` | ✅ | Unique service name (used for folder/file names) |
1456
- | `schema` | `string` \| `string[]` | ✅ | GraphQL schema URL or file path |
1457
- | `endpoint` | `string` | ✅ | GraphQL endpoint URL for queries |
1458
- | `documents` | `string[]` | ❌ | Glob patterns for GraphQL query files |
1459
- | `headers` | `Record<string, string>` \| `() => Record<string, string>` | ❌ | Custom headers for schema introspection and queries |
1460
- | `codegen.client` | `CodegenClientConfig` | ❌ | Custom codegen configuration for client types |
1461
- | `codegen.clientSDK` | `GenericSdkConfig` | ❌ | Custom codegen configuration for SDK generation |
1462
-
1463
- ## 🛠️ GraphQL Config (Optional but Recommended)
1464
-
1465
- To enable GraphQL language features in your IDE (autocompletion, validation, go-to definition), create a `graphql.config.ts` file in your project root:
1466
-
1467
- ### For Single Service (Main GraphQL Server Only)
1468
-
1469
- ```typescript
1470
- // graphql.config.ts
1471
- import type { IGraphQLConfig } from 'graphql-config'
1472
-
1473
- export default <IGraphQLConfig> {
1474
- schema: ['./.nuxt/graphql/schema.graphql'],
1475
- documents: ['./app/graphql/**/*.{graphql,js,ts,jsx,tsx}'],
1476
- exclude: ['./app/graphql/external/**/*'] // Exclude external service documents
1477
- }
1478
- ```
1479
-
1480
- ### For Multi-Service Setup
1481
-
1482
- ```typescript
1483
- // graphql.config.ts
1484
- import type { IGraphQLConfig } from 'graphql-config'
1485
-
1486
- export default <IGraphQLConfig> {
1487
- projects: {
1488
- // Main GraphQL server
1489
- default: {
1490
- schema: ['./.nuxt/graphql/schema.graphql'],
1491
- documents: ['./app/graphql/default/**/*.{graphql,js,ts,jsx,tsx}']
1492
- },
1493
- // External services
1494
- github: {
1495
- schema: [
1496
- // Use downloaded schema if available, otherwise use remote
1497
- './.nuxt/graphql/schemas/github.graphql',
1498
- // Fallback to remote if local doesn't exist
1499
- 'https://docs.github.com/public/schema.docs.graphql'
1500
- ],
1501
- documents: ['./app/graphql/external/github/**/*.graphql']
1502
- },
1503
- countries: {
1504
- schema: ['./.nuxt/graphql/schemas/countries.graphql'],
1505
- documents: ['./app/graphql/external/countries/**/*.graphql']
1506
- }
1507
- }
1508
- }
1509
- ```
1510
-
1511
- ### Schema Paths for Different Download Modes
1512
-
1513
- - **Downloaded schemas**: `./.nuxt/graphql/schemas/[serviceName].graphql`
1514
- - **Custom download path**: Use your `downloadPath` configuration
1515
- - **Remote fallback**: Include remote URL as second option
1516
-
1517
- This configuration enables:
1518
- - 🎯 **Service-specific validation**: Each GraphQL service gets its own validation rules
1519
- - 🚀 **IDE autocompletion**: Full IntelliSense for queries and mutations
1520
- - ✅ **Real-time validation**: Catch GraphQL errors while typing
1521
- - 🔍 **Go-to definition**: Navigate to type definitions across services
1522
-
1523
- ## 🛠️ VS Code Extensions
1524
-
1525
- For the best development experience with GraphQL, install these recommended VS Code extensions:
1526
-
1527
- - **[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
1528
- - **[GraphQL: Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql-syntax)** - Adds syntax highlighting for GraphQL queries, mutations, subscriptions, and schema files
1529
-
1530
- These extensions will enable:
1531
- - 🎨 Syntax highlighting for `.graphql` files
1532
- - 📝 IntelliSense and autocompletion based on your schema
1533
- - ✅ Real-time validation of GraphQL queries
1534
- - 🔍 Go-to definition for types and fields
1535
- - 💡 Hover information for GraphQL elements
1536
-
1537
- ---
1538
-
1539
- ### 🌟 Thank You
1540
-
1541
- Thank you for using and developing this project. Every contribution makes the GraphQL ecosystem stronger!
1542
-
1543
- ## Sponsors
1544
-
1545
- <p align="center">
1546
- <a href="https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg">
1547
- <img src='https://cdn.jsdelivr.net/gh/productdevbook/static/sponsors.svg?t=1721043966'/>
1548
- </a>
1549
- </p>
1550
-
1551
- ## License
415
+ ## License
1552
416
 
1553
417
  [MIT](./LICENSE) License © 2023 [productdevbook](https://github.com/productdevbook)
1554
418
 
1555
419
  <!-- Badges -->
1556
-
1557
420
  [npm-version-src]: https://img.shields.io/npm/v/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
1558
421
  [npm-version-href]: https://npmjs.com/package/nitro-graphql
1559
422
  [npm-downloads-src]: https://img.shields.io/npm/dm/nitro-graphql?style=flat&colorA=080f12&colorB=1fa669
@@ -1561,5 +424,4 @@ Thank you for using and developing this project. Every contribution makes the Gr
1561
424
  [bundle-src]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1562
425
  [bundle-href]: https://deno.bundlejs.com/badge?q=nitro-graphql@0.0.4
1563
426
  [license-src]: https://img.shields.io/github/license/productdevbook/nitro-graphql.svg?style=flat&colorA=080f12&colorB=1fa669
1564
- [license-href]: https://github.com/productdevbook/nitro-graphql/blob/main/LICENSE
1565
- [jsdocs-href]: https://www.jsdocs.io/package/nitro-graphql
427
+ [license-href]: https://github.com/productdevbook/nitro-graphql/blob/main/LICENSE