nitro-graphql 2.0.0-beta.24 → 2.0.0-beta.26
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 +127 -520
- package/dist/define.d.mts +16 -14
- package/dist/define.mjs +16 -14
- package/dist/rollup.mjs +2 -2
- package/dist/routes/apollo-server.d.mts +2 -2
- package/dist/routes/graphql-yoga.mjs +4 -0
- package/dist/routes/health.d.mts +2 -2
- package/dist/setup.mjs +37 -46
- package/dist/types/define.d.mts +12 -1
- package/dist/types/define.mjs +1 -0
- package/dist/types/index.d.mts +1 -1
- package/dist/types/index.mjs +1 -0
- package/dist/types/standard-schema.mjs +1 -0
- package/dist/utils/client-codegen.d.mts +4 -1
- package/dist/utils/client-codegen.mjs +2 -2
- package/dist/utils/errors.d.mts +73 -0
- package/dist/utils/errors.mjs +89 -0
- package/dist/utils/index.d.mts +2 -1
- package/dist/utils/index.mjs +16 -5
- package/dist/utils/server-codegen.mjs +1 -1
- package/dist/utils/type-generation.d.mts +7 -2
- package/dist/utils/type-generation.mjs +20 -19
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
|
|
57
57
|
**GraphQL Yoga (recommended):**
|
|
58
58
|
```bash
|
|
59
|
-
pnpm add nitro-graphql graphql-yoga graphql
|
|
59
|
+
pnpm add nitro-graphql@beta graphql-yoga graphql graphql-config
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
**Apollo Server:**
|
|
63
63
|
```bash
|
|
64
|
-
pnpm add nitro-graphql @apollo/server @apollo/utils.withrequired graphql
|
|
64
|
+
pnpm add nitro-graphql@beta @apollo/server @apollo/utils.withrequired graphql graphql-config
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
### 2. Configure
|
|
@@ -71,13 +71,15 @@ pnpm add nitro-graphql @apollo/server @apollo/utils.withrequired graphql
|
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
73
|
// nitro.config.ts
|
|
74
|
+
import graphql from 'nitro-graphql'
|
|
74
75
|
import { defineNitroConfig } from 'nitro/config'
|
|
75
76
|
|
|
76
77
|
export default defineNitroConfig({
|
|
77
|
-
modules: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
modules: [
|
|
79
|
+
graphql({
|
|
80
|
+
framework: 'graphql-yoga', // or 'apollo-server'
|
|
81
|
+
}),
|
|
82
|
+
],
|
|
81
83
|
})
|
|
82
84
|
```
|
|
83
85
|
|
|
@@ -90,18 +92,20 @@ export default defineNitroConfig({
|
|
|
90
92
|
// vite.config.ts
|
|
91
93
|
import { defineConfig } from 'vite'
|
|
92
94
|
import { nitro } from 'nitro/vite'
|
|
93
|
-
import
|
|
95
|
+
import graphql from 'nitro-graphql'
|
|
96
|
+
import { graphql as graphqlVite } from 'nitro-graphql/vite'
|
|
94
97
|
|
|
95
98
|
export default defineConfig({
|
|
96
99
|
plugins: [
|
|
97
|
-
|
|
100
|
+
graphqlVite(), // ⚠️ Must be before nitro()
|
|
98
101
|
nitro(),
|
|
99
102
|
],
|
|
100
103
|
nitro: {
|
|
101
|
-
modules: [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
modules: [
|
|
105
|
+
graphql({
|
|
106
|
+
framework: 'graphql-yoga',
|
|
107
|
+
}),
|
|
108
|
+
],
|
|
105
109
|
},
|
|
106
110
|
})
|
|
107
111
|
```
|
|
@@ -145,6 +149,8 @@ type Mutation {
|
|
|
145
149
|
|
|
146
150
|
```ts
|
|
147
151
|
// server/graphql/hello.resolver.ts
|
|
152
|
+
import { defineResolver } from 'nitro-graphql/define'
|
|
153
|
+
|
|
148
154
|
export const helloResolver = defineResolver({
|
|
149
155
|
Query: {
|
|
150
156
|
hello: () => 'Hello from GraphQL!',
|
|
@@ -175,6 +181,7 @@ Try these working examples:
|
|
|
175
181
|
| [**Vite + Nitro**](./playgrounds/vite/) | Vite with Nitro GraphQL integration | `cd playgrounds/vite && pnpm dev` |
|
|
176
182
|
| [**Nuxt Integration**](./playgrounds/nuxt/) | Full Nuxt app with client types | `pnpm playground:nuxt` |
|
|
177
183
|
| [**Apollo Federation**](./playgrounds/federation/) | Federated GraphQL services | `pnpm playground:federation` |
|
|
184
|
+
| [**Drizzle ORM**](./examples/drizzle-orm/) | Drizzle ORM + Zod validation integration | `cd examples/drizzle-orm && pnpm dev` |
|
|
178
185
|
|
|
179
186
|
### 🧪 Test Projects
|
|
180
187
|
|
|
@@ -215,6 +222,8 @@ extend type Mutation {
|
|
|
215
222
|
### 2. Create Resolvers
|
|
216
223
|
```ts
|
|
217
224
|
// server/graphql/users/user.resolver.ts
|
|
225
|
+
import { defineQuery, defineMutation } from 'nitro-graphql/define'
|
|
226
|
+
|
|
218
227
|
export const userQueries = defineQuery({
|
|
219
228
|
users: async (_, __, { storage }) => {
|
|
220
229
|
return await storage.getItem('users') || []
|
|
@@ -276,12 +285,17 @@ Disable all scaffold files for library/module development:
|
|
|
276
285
|
|
|
277
286
|
```ts
|
|
278
287
|
// nitro.config.ts
|
|
288
|
+
import graphql from 'nitro-graphql'
|
|
289
|
+
import { defineNitroConfig } from 'nitro/config'
|
|
290
|
+
|
|
279
291
|
export default defineNitroConfig({
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
292
|
+
modules: [
|
|
293
|
+
graphql({
|
|
294
|
+
framework: 'graphql-yoga',
|
|
295
|
+
scaffold: false, // Disable all scaffold files
|
|
296
|
+
clientUtils: false, // Disable client utilities
|
|
297
|
+
}),
|
|
298
|
+
],
|
|
285
299
|
})
|
|
286
300
|
```
|
|
287
301
|
|
|
@@ -290,37 +304,42 @@ export default defineNitroConfig({
|
|
|
290
304
|
Control each file individually:
|
|
291
305
|
|
|
292
306
|
```ts
|
|
307
|
+
import graphql from 'nitro-graphql'
|
|
308
|
+
import { defineNitroConfig } from 'nitro/config'
|
|
309
|
+
|
|
293
310
|
export default defineNitroConfig({
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
// Scaffold files
|
|
298
|
-
scaffold: {
|
|
299
|
-
graphqlConfig: false, // Don't generate graphql.config.ts
|
|
300
|
-
serverSchema: true, // Generate server/graphql/schema.ts
|
|
301
|
-
serverConfig: true, // Generate server/graphql/config.ts
|
|
302
|
-
serverContext: false, // Don't generate server/graphql/context.ts
|
|
303
|
-
},
|
|
311
|
+
modules: [
|
|
312
|
+
graphql({
|
|
313
|
+
framework: 'graphql-yoga',
|
|
304
314
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
315
|
+
// Scaffold files
|
|
316
|
+
scaffold: {
|
|
317
|
+
graphqlConfig: false, // Don't generate graphql.config.ts
|
|
318
|
+
serverSchema: true, // Generate server/graphql/schema.ts
|
|
319
|
+
serverConfig: true, // Generate server/graphql/config.ts
|
|
320
|
+
serverContext: false, // Don't generate server/graphql/context.ts
|
|
321
|
+
},
|
|
310
322
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
323
|
+
// Client utilities (Nuxt only)
|
|
324
|
+
clientUtils: {
|
|
325
|
+
index: true, // Generate app/graphql/index.ts
|
|
326
|
+
ofetch: false, // Don't generate ofetch wrappers
|
|
327
|
+
},
|
|
316
328
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
329
|
+
// SDK files
|
|
330
|
+
sdk: {
|
|
331
|
+
main: true, // Generate default SDK
|
|
332
|
+
external: true, // Generate external service SDKs
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
// Type files
|
|
336
|
+
types: {
|
|
337
|
+
server: true, // Generate server types
|
|
338
|
+
client: true, // Generate client types
|
|
339
|
+
external: true, // Generate external service types
|
|
340
|
+
},
|
|
341
|
+
}),
|
|
342
|
+
],
|
|
324
343
|
})
|
|
325
344
|
```
|
|
326
345
|
|
|
@@ -329,34 +348,39 @@ export default defineNitroConfig({
|
|
|
329
348
|
Customize where files are generated:
|
|
330
349
|
|
|
331
350
|
```ts
|
|
351
|
+
import graphql from 'nitro-graphql'
|
|
352
|
+
import { defineNitroConfig } from 'nitro/config'
|
|
353
|
+
|
|
332
354
|
export default defineNitroConfig({
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
// Method 1: Global paths (affects all files)
|
|
337
|
-
paths: {
|
|
338
|
-
serverGraphql: 'src/server/graphql',
|
|
339
|
-
clientGraphql: 'src/client/graphql',
|
|
340
|
-
buildDir: '.build',
|
|
341
|
-
typesDir: '.build/types',
|
|
342
|
-
},
|
|
355
|
+
modules: [
|
|
356
|
+
graphql({
|
|
357
|
+
framework: 'graphql-yoga',
|
|
343
358
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
359
|
+
// Method 1: Global paths (affects all files)
|
|
360
|
+
paths: {
|
|
361
|
+
serverGraphql: 'src/server/graphql',
|
|
362
|
+
clientGraphql: 'src/client/graphql',
|
|
363
|
+
buildDir: '.build',
|
|
364
|
+
typesDir: '.build/types',
|
|
365
|
+
},
|
|
349
366
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
367
|
+
// Method 2: Specific file paths
|
|
368
|
+
scaffold: {
|
|
369
|
+
serverSchema: 'lib/graphql/schema.ts',
|
|
370
|
+
serverConfig: 'lib/graphql/config.ts',
|
|
371
|
+
},
|
|
354
372
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
373
|
+
sdk: {
|
|
374
|
+
main: 'app/graphql/organization/sdk.ts',
|
|
375
|
+
external: 'app/graphql/{serviceName}/client-sdk.ts',
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
types: {
|
|
379
|
+
server: 'types/graphql-server.d.ts',
|
|
380
|
+
client: 'types/graphql-client.d.ts',
|
|
381
|
+
},
|
|
382
|
+
}),
|
|
383
|
+
],
|
|
360
384
|
})
|
|
361
385
|
```
|
|
362
386
|
|
|
@@ -512,6 +536,8 @@ Create reusable GraphQL directives:
|
|
|
512
536
|
|
|
513
537
|
```ts
|
|
514
538
|
// server/graphql/directives/auth.directive.ts
|
|
539
|
+
import { defineDirective } from 'nitro-graphql/define'
|
|
540
|
+
|
|
515
541
|
export const authDirective = defineDirective({
|
|
516
542
|
name: 'auth',
|
|
517
543
|
locations: ['FIELD_DEFINITION'],
|
|
@@ -569,14 +595,19 @@ Build federated GraphQL services:
|
|
|
569
595
|
|
|
570
596
|
```ts
|
|
571
597
|
// nitro.config.ts
|
|
598
|
+
import graphql from 'nitro-graphql'
|
|
599
|
+
import { defineNitroConfig } from 'nitro/config'
|
|
600
|
+
|
|
572
601
|
export default defineNitroConfig({
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
602
|
+
modules: [
|
|
603
|
+
graphql({
|
|
604
|
+
framework: 'apollo-server',
|
|
605
|
+
federation: {
|
|
606
|
+
enabled: true,
|
|
607
|
+
serviceName: 'users-service',
|
|
608
|
+
},
|
|
609
|
+
}),
|
|
610
|
+
],
|
|
580
611
|
})
|
|
581
612
|
```
|
|
582
613
|
|
|
@@ -586,7 +617,11 @@ export default defineNitroConfig({
|
|
|
586
617
|
|
|
587
618
|
### Core Utilities
|
|
588
619
|
|
|
589
|
-
|
|
620
|
+
> **⚠️ Breaking Change**: Utilities are **NOT auto-imported**. You must explicitly import them from `nitro-graphql/define`:
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
import { defineResolver, defineQuery, defineMutation, defineType, defineDirective } from 'nitro-graphql/define'
|
|
624
|
+
```
|
|
590
625
|
|
|
591
626
|
| Function | Purpose | Example |
|
|
592
627
|
|----------|---------|---------|
|
|
@@ -595,6 +630,11 @@ All utilities are auto-imported in resolver files:
|
|
|
595
630
|
| `defineMutation` | Mutation-only resolvers | `defineMutation({ createUser: (...) => {...} })` |
|
|
596
631
|
| `defineType` | Custom type resolvers | `defineType({ User: { posts: (parent) => [...] } })` |
|
|
597
632
|
| `defineDirective` | Custom directives | `defineDirective({ name: 'auth', ... })` |
|
|
633
|
+
| `defineGraphQLConfig` | GraphQL server config | `defineGraphQLConfig({ maskedErrors: {...} })` |
|
|
634
|
+
| `defineSchema` | Schema with Zod integration | `defineSchema({ Book: selectBookSchema })` |
|
|
635
|
+
|
|
636
|
+
**Additional Utilities** from `nitro-graphql/utils`:
|
|
637
|
+
- `createDefaultMaskError()` - Error handler for ZodError and HTTPError (use in `defineGraphQLConfig`)
|
|
598
638
|
|
|
599
639
|
### Type Generation
|
|
600
640
|
|
|
@@ -648,10 +688,19 @@ server/
|
|
|
648
688
|
- ✅ Check file naming: `*.graphql`, `*.resolver.ts`
|
|
649
689
|
- ✅ Verify exports are named exports
|
|
650
690
|
|
|
651
|
-
**Import errors**
|
|
652
|
-
- ✅
|
|
691
|
+
**Import errors / "defineQuery is not defined"**
|
|
692
|
+
- ✅ **Requires explicit imports**: Add `import { defineQuery } from 'nitro-graphql/define'` to resolver files
|
|
693
|
+
- ✅ Use correct import path: `nitro-graphql/define` (not `nitro-graphql`)
|
|
653
694
|
- ✅ Use named exports in resolvers
|
|
654
695
|
|
|
696
|
+
Example fix:
|
|
697
|
+
```typescript
|
|
698
|
+
// Add this to the top of your resolver file
|
|
699
|
+
import { defineQuery, defineMutation } from 'nitro-graphql/define'
|
|
700
|
+
|
|
701
|
+
export const myQueries = defineQuery({ ... })
|
|
702
|
+
```
|
|
703
|
+
|
|
655
704
|
**Vite: "Parse failure: Expected ';', '}' or <eof>" on GraphQL files**
|
|
656
705
|
- ✅ Add `graphql()` plugin from `nitro-graphql/vite`
|
|
657
706
|
- ✅ Ensure `graphql()` is placed **before** `nitro()` in plugins array
|
|
@@ -748,448 +797,6 @@ This package powers production applications:
|
|
|
748
797
|
|
|
749
798
|
- [**Nitroping**](https://github.com/productdevbook/nitroping) - Self-hosted push notification service
|
|
750
799
|
|
|
751
|
-
## 🤖 Using Claude Code
|
|
752
|
-
|
|
753
|
-
Speed up development with [Claude Code](https://claude.ai/code) — AI-powered assistance for setting up and building with nitro-graphql.
|
|
754
|
-
|
|
755
|
-
### Quick Setup Prompts
|
|
756
|
-
|
|
757
|
-
Copy and paste these prompts into Claude Code to scaffold a complete GraphQL API.
|
|
758
|
-
|
|
759
|
-
**💡 Tip**: After pasting, Claude Code will execute step-by-step and validate each action.
|
|
760
|
-
|
|
761
|
-
<details>
|
|
762
|
-
<summary>🟢 <strong>Nuxt Project</strong></summary>
|
|
763
|
-
|
|
764
|
-
```
|
|
765
|
-
## GOAL
|
|
766
|
-
Set up nitro-graphql in this Nuxt project with a User management GraphQL API.
|
|
767
|
-
|
|
768
|
-
## PREREQUISITES
|
|
769
|
-
Check if this is a Nuxt project by looking for nuxt.config.ts in the root.
|
|
770
|
-
|
|
771
|
-
## STEP 1: INSTALL DEPENDENCIES
|
|
772
|
-
Action: Run this command
|
|
773
|
-
Command: pnpm add nitro-graphql graphql-yoga graphql
|
|
774
|
-
Validation: Check package.json contains these packages
|
|
775
|
-
|
|
776
|
-
## STEP 2: CONFIGURE NUXT
|
|
777
|
-
File: nuxt.config.ts
|
|
778
|
-
Action: EDIT (add to existing config, don't replace)
|
|
779
|
-
Add these properties:
|
|
780
|
-
|
|
781
|
-
export default defineNuxtConfig({
|
|
782
|
-
modules: ['nitro-graphql/nuxt'], // Add this module
|
|
783
|
-
nitro: {
|
|
784
|
-
graphql: {
|
|
785
|
-
framework: 'graphql-yoga',
|
|
786
|
-
},
|
|
787
|
-
},
|
|
788
|
-
})
|
|
789
|
-
|
|
790
|
-
Validation: Check the file has modules array and nitro.graphql config
|
|
791
|
-
|
|
792
|
-
## STEP 3: CREATE SCHEMA
|
|
793
|
-
File: server/graphql/schema.graphql
|
|
794
|
-
Action: CREATE NEW FILE (create server/graphql/ directory if needed)
|
|
795
|
-
Content:
|
|
796
|
-
|
|
797
|
-
type User {
|
|
798
|
-
id: ID!
|
|
799
|
-
name: String!
|
|
800
|
-
email: String!
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
type Query {
|
|
804
|
-
users: [User!]!
|
|
805
|
-
user(id: ID!): User
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
type Mutation {
|
|
809
|
-
_empty: String
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
Validation: File should be in server/graphql/ directory
|
|
813
|
-
|
|
814
|
-
## STEP 4: CREATE CONTEXT (Optional but recommended)
|
|
815
|
-
File: server/graphql/context.ts
|
|
816
|
-
Action: CREATE NEW FILE (auto-generated on first run, but create manually for clarity)
|
|
817
|
-
Content:
|
|
818
|
-
|
|
819
|
-
// Extend H3 event context with custom properties
|
|
820
|
-
declare module 'h3' {
|
|
821
|
-
interface H3EventContext {
|
|
822
|
-
// Add your custom context properties here
|
|
823
|
-
// Example:
|
|
824
|
-
// db?: Database
|
|
825
|
-
// auth?: { userId: string }
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
Note: This file lets you add custom properties to resolver context
|
|
830
|
-
Validation: File exists in server/graphql/
|
|
831
|
-
|
|
832
|
-
## STEP 5: CREATE CONFIG (Optional)
|
|
833
|
-
File: server/graphql/config.ts
|
|
834
|
-
Action: CREATE NEW FILE (auto-generated, customize if needed)
|
|
835
|
-
Content:
|
|
836
|
-
|
|
837
|
-
// Custom GraphQL Yoga configuration
|
|
838
|
-
export default defineGraphQLConfig({
|
|
839
|
-
// Custom context enhancer, plugins, etc.
|
|
840
|
-
// See: https://the-guild.dev/graphql/yoga-server/docs
|
|
841
|
-
})
|
|
842
|
-
|
|
843
|
-
Note: Use this to customize GraphQL Yoga options
|
|
844
|
-
Validation: File exists in server/graphql/
|
|
845
|
-
|
|
846
|
-
## STEP 6: CREATE RESOLVERS
|
|
847
|
-
File: server/graphql/users.resolver.ts
|
|
848
|
-
Action: CREATE NEW FILE
|
|
849
|
-
Content:
|
|
850
|
-
|
|
851
|
-
// ⚠️ CRITICAL: Use NAMED EXPORTS (not default export)
|
|
852
|
-
export const userQueries = defineQuery({
|
|
853
|
-
users: async (_, __, context) => {
|
|
854
|
-
// context is H3EventContext - access event, storage, etc.
|
|
855
|
-
return [
|
|
856
|
-
{ id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
857
|
-
{ id: '2', name: 'Jane Smith', email: 'jane@example.com' }
|
|
858
|
-
]
|
|
859
|
-
},
|
|
860
|
-
user: async (_, { id }, context) => {
|
|
861
|
-
// Third parameter is context (H3EventContext)
|
|
862
|
-
const users = [
|
|
863
|
-
{ id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
864
|
-
{ id: '2', name: 'Jane Smith', email: 'jane@example.com' }
|
|
865
|
-
]
|
|
866
|
-
return users.find(u => u.id === id) || null
|
|
867
|
-
}
|
|
868
|
-
})
|
|
869
|
-
|
|
870
|
-
Validation: File ends with .resolver.ts and uses named export
|
|
871
|
-
|
|
872
|
-
## STEP 7: START DEV SERVER
|
|
873
|
-
Command: pnpm dev
|
|
874
|
-
Expected Output: Server starts on http://localhost:3000
|
|
875
|
-
Wait for: "Nitro built in X ms" message
|
|
876
|
-
Note: context.ts and config.ts will auto-generate if you skipped steps 4-5
|
|
877
|
-
|
|
878
|
-
## VALIDATION CHECKLIST
|
|
879
|
-
- [ ] Navigate to http://localhost:3000/api/graphql - should show GraphQL playground
|
|
880
|
-
- [ ] Health check: http://localhost:3000/api/graphql/health - should return OK
|
|
881
|
-
- [ ] Run this query in playground:
|
|
882
|
-
```graphql
|
|
883
|
-
query {
|
|
884
|
-
users {
|
|
885
|
-
id
|
|
886
|
-
name
|
|
887
|
-
email
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
```
|
|
891
|
-
Expected: Returns 2 users
|
|
892
|
-
- [ ] Check .nuxt/types/nitro-graphql-server.d.ts exists (types auto-generated)
|
|
893
|
-
|
|
894
|
-
## FILE STRUCTURE CREATED
|
|
895
|
-
```
|
|
896
|
-
server/
|
|
897
|
-
graphql/
|
|
898
|
-
schema.graphql ← GraphQL type definitions
|
|
899
|
-
context.ts ← H3 event context augmentation (optional)
|
|
900
|
-
config.ts ← GraphQL Yoga config (optional)
|
|
901
|
-
users.resolver.ts ← Query resolvers
|
|
902
|
-
.nuxt/
|
|
903
|
-
types/
|
|
904
|
-
nitro-graphql-server.d.ts ← Auto-generated types
|
|
905
|
-
graphql.config.ts ← Auto-generated (for IDE tooling)
|
|
906
|
-
```
|
|
907
|
-
|
|
908
|
-
## CRITICAL RULES (MUST FOLLOW)
|
|
909
|
-
❌ DO NOT use default exports in resolvers
|
|
910
|
-
Wrong: export default defineQuery({...})
|
|
911
|
-
Right: export const userQueries = defineQuery({...})
|
|
912
|
-
|
|
913
|
-
❌ DO NOT name files without .resolver.ts extension
|
|
914
|
-
Wrong: users.ts or user-resolver.ts
|
|
915
|
-
Right: users.resolver.ts or user.resolver.ts
|
|
916
|
-
|
|
917
|
-
✅ DO use named exports for all resolvers
|
|
918
|
-
✅ DO place files in server/graphql/ directory
|
|
919
|
-
✅ DO restart dev server if types don't generate
|
|
920
|
-
|
|
921
|
-
## TROUBLESHOOTING
|
|
922
|
-
Issue: "GraphQL endpoint returns 404"
|
|
923
|
-
Fix: Ensure 'nitro-graphql/nuxt' is in modules array (not just 'nitro-graphql')
|
|
924
|
-
|
|
925
|
-
Issue: "defineQuery is not defined"
|
|
926
|
-
Fix: Restart dev server - auto-imports need to regenerate
|
|
927
|
-
|
|
928
|
-
Issue: "Types not generating"
|
|
929
|
-
Fix: Check .nuxt/types/nitro-graphql-server.d.ts exists, if not restart dev server
|
|
930
|
-
|
|
931
|
-
Issue: "Module not found: nitro-graphql"
|
|
932
|
-
Fix: Run pnpm install again, check package.json has the package
|
|
933
|
-
|
|
934
|
-
## NEXT STEPS (After Setup Works)
|
|
935
|
-
1. Add mutations: "Add createUser and deleteUser mutations with H3 storage"
|
|
936
|
-
2. Extend context: "Add database connection to context.ts and use it in resolvers"
|
|
937
|
-
3. Use types: "Import and use TypeScript types from #graphql/server in resolvers"
|
|
938
|
-
4. Add auth: "Add authentication middleware using context in resolvers"
|
|
939
|
-
5. Custom config: "Configure GraphQL Yoga plugins in config.ts"
|
|
940
|
-
|
|
941
|
-
Now implement this setup step-by-step.
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
</details>
|
|
945
|
-
|
|
946
|
-
<details>
|
|
947
|
-
<summary>⚡ <strong>Nitro Project</strong></summary>
|
|
948
|
-
|
|
949
|
-
```
|
|
950
|
-
Set up nitro-graphql in this Nitro project following these exact specifications:
|
|
951
|
-
|
|
952
|
-
INSTALLATION:
|
|
953
|
-
1. Run: pnpm add nitro-graphql graphql-yoga graphql
|
|
954
|
-
|
|
955
|
-
CONFIGURATION (nitro.config.ts):
|
|
956
|
-
import { defineNitroConfig } from 'nitro/config'
|
|
957
|
-
|
|
958
|
-
export default defineNitroConfig({
|
|
959
|
-
modules: ['nitro-graphql'],
|
|
960
|
-
graphql: {
|
|
961
|
-
framework: 'graphql-yoga',
|
|
962
|
-
},
|
|
963
|
-
})
|
|
964
|
-
|
|
965
|
-
SCHEMA (server/graphql/schema.graphql):
|
|
966
|
-
type Product {
|
|
967
|
-
id: ID!
|
|
968
|
-
name: String!
|
|
969
|
-
price: Float!
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
input CreateProductInput {
|
|
973
|
-
name: String!
|
|
974
|
-
price: Float!
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
type Query {
|
|
978
|
-
products: [Product!]!
|
|
979
|
-
product(id: ID!): Product
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
type Mutation {
|
|
983
|
-
createProduct(input: CreateProductInput!): Product!
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
RESOLVERS (server/graphql/products.resolver.ts):
|
|
987
|
-
// Use NAMED EXPORTS only
|
|
988
|
-
export const productQueries = defineQuery({
|
|
989
|
-
products: async (_, __, context) => {
|
|
990
|
-
// Access H3 event context
|
|
991
|
-
const products = await context.storage?.getItem('products') || []
|
|
992
|
-
return products
|
|
993
|
-
},
|
|
994
|
-
product: async (_, { id }, context) => {
|
|
995
|
-
const products = await context.storage?.getItem('products') || []
|
|
996
|
-
return products.find(p => p.id === id)
|
|
997
|
-
}
|
|
998
|
-
})
|
|
999
|
-
|
|
1000
|
-
export const productMutations = defineMutation({
|
|
1001
|
-
createProduct: async (_, { input }, context) => {
|
|
1002
|
-
const products = await context.storage?.getItem('products') || []
|
|
1003
|
-
const product = {
|
|
1004
|
-
id: Date.now().toString(),
|
|
1005
|
-
...input
|
|
1006
|
-
}
|
|
1007
|
-
products.push(product)
|
|
1008
|
-
await context.storage?.setItem('products', products)
|
|
1009
|
-
return product
|
|
1010
|
-
}
|
|
1011
|
-
})
|
|
1012
|
-
|
|
1013
|
-
KEY RULES:
|
|
1014
|
-
- Files: *.graphql for schemas, *.resolver.ts for resolvers
|
|
1015
|
-
- MUST use named exports (not default export)
|
|
1016
|
-
- defineQuery and defineMutation are auto-imported
|
|
1017
|
-
- Context is the third parameter (access H3 event context)
|
|
1018
|
-
- Endpoint: http://localhost:3000/api/graphql
|
|
1019
|
-
|
|
1020
|
-
Now implement this setup.
|
|
1021
|
-
```
|
|
1022
|
-
|
|
1023
|
-
</details>
|
|
1024
|
-
|
|
1025
|
-
<details>
|
|
1026
|
-
<summary>🎮 <strong>Apollo Server Setup</strong></summary>
|
|
1027
|
-
|
|
1028
|
-
```
|
|
1029
|
-
Set up nitro-graphql with Apollo Server following these exact specifications:
|
|
1030
|
-
|
|
1031
|
-
INSTALLATION:
|
|
1032
|
-
1. Run: pnpm add nitro-graphql @apollo/server @apollo/utils.withrequired graphql
|
|
1033
|
-
|
|
1034
|
-
CONFIGURATION (nitro.config.ts):
|
|
1035
|
-
import { defineNitroConfig } from 'nitro/config'
|
|
1036
|
-
|
|
1037
|
-
export default defineNitroConfig({
|
|
1038
|
-
modules: ['nitro-graphql'],
|
|
1039
|
-
graphql: {
|
|
1040
|
-
framework: 'apollo-server',
|
|
1041
|
-
},
|
|
1042
|
-
})
|
|
1043
|
-
|
|
1044
|
-
SCHEMA (server/graphql/schema.graphql):
|
|
1045
|
-
type Book {
|
|
1046
|
-
id: ID!
|
|
1047
|
-
title: String!
|
|
1048
|
-
author: String!
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
type Query {
|
|
1052
|
-
books: [Book!]!
|
|
1053
|
-
book(id: ID!): Book
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
type Mutation {
|
|
1057
|
-
addBook(title: String!, author: String!): Book!
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
RESOLVERS (server/graphql/books.resolver.ts):
|
|
1061
|
-
// IMPORTANT: Use NAMED EXPORTS
|
|
1062
|
-
export const bookResolver = defineResolver({
|
|
1063
|
-
Query: {
|
|
1064
|
-
books: async () => {
|
|
1065
|
-
return [
|
|
1066
|
-
{ id: '1', title: '1984', author: 'George Orwell' }
|
|
1067
|
-
]
|
|
1068
|
-
},
|
|
1069
|
-
book: async (_, { id }) => {
|
|
1070
|
-
return { id, title: '1984', author: 'George Orwell' }
|
|
1071
|
-
}
|
|
1072
|
-
},
|
|
1073
|
-
Mutation: {
|
|
1074
|
-
addBook: async (_, { title, author }) => {
|
|
1075
|
-
return {
|
|
1076
|
-
id: Date.now().toString(),
|
|
1077
|
-
title,
|
|
1078
|
-
author
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
})
|
|
1083
|
-
|
|
1084
|
-
KEY RULES:
|
|
1085
|
-
- framework: 'apollo-server' in config
|
|
1086
|
-
- defineResolver for complete resolver maps
|
|
1087
|
-
- Named exports required (export const name = ...)
|
|
1088
|
-
- Apollo Sandbox: http://localhost:3000/api/graphql
|
|
1089
|
-
- Supports Apollo Federation with federation: { enabled: true }
|
|
1090
|
-
|
|
1091
|
-
Now implement this setup.
|
|
1092
|
-
```
|
|
1093
|
-
|
|
1094
|
-
</details>
|
|
1095
|
-
|
|
1096
|
-
<details>
|
|
1097
|
-
<summary>🔄 <strong>Add Feature to Existing Setup</strong></summary>
|
|
1098
|
-
|
|
1099
|
-
```
|
|
1100
|
-
Add a complete blog posts feature to my nitro-graphql API following these specifications:
|
|
1101
|
-
|
|
1102
|
-
SCHEMA (server/graphql/posts/post.graphql):
|
|
1103
|
-
type Post {
|
|
1104
|
-
id: ID!
|
|
1105
|
-
title: String!
|
|
1106
|
-
content: String!
|
|
1107
|
-
authorId: ID!
|
|
1108
|
-
createdAt: String!
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
input CreatePostInput {
|
|
1112
|
-
title: String!
|
|
1113
|
-
content: String!
|
|
1114
|
-
authorId: ID!
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
input UpdatePostInput {
|
|
1118
|
-
title: String
|
|
1119
|
-
content: String
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
extend type Query {
|
|
1123
|
-
posts(limit: Int = 10, offset: Int = 0): [Post!]!
|
|
1124
|
-
post(id: ID!): Post
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
extend type Mutation {
|
|
1128
|
-
createPost(input: CreatePostInput!): Post!
|
|
1129
|
-
updatePost(id: ID!, input: UpdatePostInput!): Post
|
|
1130
|
-
deletePost(id: ID!): Boolean!
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
RESOLVERS (server/graphql/posts/post.resolver.ts):
|
|
1134
|
-
// Use NAMED EXPORTS
|
|
1135
|
-
export const postQueries = defineQuery({
|
|
1136
|
-
posts: async (_, { limit, offset }, context) => {
|
|
1137
|
-
const posts = await context.storage?.getItem('posts') || []
|
|
1138
|
-
return posts.slice(offset, offset + limit)
|
|
1139
|
-
},
|
|
1140
|
-
post: async (_, { id }, context) => {
|
|
1141
|
-
const posts = await context.storage?.getItem('posts') || []
|
|
1142
|
-
return posts.find(p => p.id === id) || null
|
|
1143
|
-
}
|
|
1144
|
-
})
|
|
1145
|
-
|
|
1146
|
-
export const postMutations = defineMutation({
|
|
1147
|
-
createPost: async (_, { input }, context) => {
|
|
1148
|
-
const posts = await context.storage?.getItem('posts') || []
|
|
1149
|
-
const post = {
|
|
1150
|
-
id: Date.now().toString(),
|
|
1151
|
-
...input,
|
|
1152
|
-
createdAt: new Date().toISOString()
|
|
1153
|
-
}
|
|
1154
|
-
posts.push(post)
|
|
1155
|
-
await context.storage?.setItem('posts', posts)
|
|
1156
|
-
return post
|
|
1157
|
-
},
|
|
1158
|
-
updatePost: async (_, { id, input }, context) => {
|
|
1159
|
-
const posts = await context.storage?.getItem('posts') || []
|
|
1160
|
-
const index = posts.findIndex(p => p.id === id)
|
|
1161
|
-
if (index === -1) return null
|
|
1162
|
-
posts[index] = { ...posts[index], ...input }
|
|
1163
|
-
await context.storage?.setItem('posts', posts)
|
|
1164
|
-
return posts[index]
|
|
1165
|
-
},
|
|
1166
|
-
deletePost: async (_, { id }, context) => {
|
|
1167
|
-
const posts = await context.storage?.getItem('posts') || []
|
|
1168
|
-
const filtered = posts.filter(p => p.id !== id)
|
|
1169
|
-
await context.storage?.setItem('posts', filtered)
|
|
1170
|
-
return filtered.length < posts.length
|
|
1171
|
-
}
|
|
1172
|
-
})
|
|
1173
|
-
|
|
1174
|
-
TYPE USAGE:
|
|
1175
|
-
After dev server restarts, types are auto-generated in:
|
|
1176
|
-
- .nitro/types/nitro-graphql-server.d.ts (server types)
|
|
1177
|
-
- .nuxt/types/nitro-graphql-server.d.ts (for Nuxt)
|
|
1178
|
-
|
|
1179
|
-
Import types:
|
|
1180
|
-
import type { Post, CreatePostInput } from '#graphql/server'
|
|
1181
|
-
|
|
1182
|
-
KEY RULES:
|
|
1183
|
-
- Use "extend type" to add to existing Query/Mutation
|
|
1184
|
-
- Named exports required
|
|
1185
|
-
- Context has H3 event properties
|
|
1186
|
-
- Types auto-generate on file changes
|
|
1187
|
-
|
|
1188
|
-
Now implement this feature.
|
|
1189
|
-
```
|
|
1190
|
-
|
|
1191
|
-
</details>
|
|
1192
|
-
|
|
1193
800
|
### Working with Your GraphQL API
|
|
1194
801
|
|
|
1195
802
|
Once set up, you can ask Claude Code for help with:
|