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 +183 -1321
- package/dist/index.js +6 -3
- package/dist/routes/apollo-server.d.ts +2 -2
- package/dist/routes/graphql-yoga.d.ts +2 -2
- package/dist/utils/directive-parser.js +4 -2
- package/package.json +1 -1
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
|
-
**
|
|
10
|
+
**The easiest way to add GraphQL to any Nitro application**
|
|
11
11
|
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25
|
+
## ✨ Why Nitro GraphQL?
|
|
41
26
|
|
|
42
|
-
|
|
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
|
-
|
|
34
|
+
## 🚀 Quick Start
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
- [**Nitro Usage**](https://x.com/productdevbook/status/1945759751393976348) - How to use Nitro GraphQL with standalone Nitro
|
|
36
|
+
### 1. Install
|
|
48
37
|
|
|
49
|
-
|
|
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
|
-
**
|
|
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
|
-
###
|
|
48
|
+
### 2. Configure
|
|
80
49
|
|
|
81
50
|
<details>
|
|
82
|
-
<summary>🔧 <strong>
|
|
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>
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
+
## 🏗️ Building Your First Feature
|
|
221
132
|
|
|
222
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
357
|
-
|
|
358
|
-
#### Using Generated Types
|
|
213
|
+
<details>
|
|
214
|
+
<summary><strong>🎭 Custom Directives</strong></summary>
|
|
359
215
|
|
|
360
|
-
|
|
216
|
+
Create reusable GraphQL directives:
|
|
361
217
|
|
|
362
|
-
**Client-side types** (`#graphql/client`):
|
|
363
218
|
```ts
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
|
|
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
|
-
|
|
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
|
|
243
|
+
<summary><strong>🌐 External GraphQL Services</strong></summary>
|
|
244
|
+
|
|
245
|
+
Connect to multiple GraphQL APIs:
|
|
414
246
|
|
|
415
247
|
```ts
|
|
416
|
-
//
|
|
417
|
-
export default
|
|
418
|
-
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
|
271
|
+
<summary><strong>🔄 Apollo Federation</strong></summary>
|
|
272
|
+
|
|
273
|
+
Build federated GraphQL services:
|
|
438
274
|
|
|
439
275
|
```ts
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
|
|
492
|
-
<summary><strong>defineResolver</strong> - Define complete resolvers</summary>
|
|
304
|
+
### Type Generation
|
|
493
305
|
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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
|
-
//
|
|
508
|
-
|
|
509
|
-
Query: {
|
|
510
|
-
// Additional query resolvers
|
|
511
|
-
},
|
|
512
|
-
})
|
|
314
|
+
// Client-side
|
|
315
|
+
import type { GetUsersQuery, CreateUserMutation } from '#graphql/client'
|
|
513
316
|
```
|
|
514
317
|
|
|
515
|
-
|
|
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
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
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
|
-
|
|
545
|
-
<summary><strong>defineMutation</strong> - Define only Mutation resolvers</summary>
|
|
341
|
+
## 🚨 Troubleshooting
|
|
546
342
|
|
|
547
|
-
|
|
548
|
-
|
|
343
|
+
<details>
|
|
344
|
+
<summary><strong>Common Issues</strong></summary>
|
|
549
345
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
-
|
|
582
|
-
<summary><strong>defineSubscription</strong> - Define Subscription resolvers</summary>
|
|
362
|
+
## 🌟 Production Usage
|
|
583
363
|
|
|
584
|
-
|
|
585
|
-
import { defineSubscription } from 'nitro-graphql/utils/define'
|
|
364
|
+
This package powers production applications:
|
|
586
365
|
|
|
587
|
-
|
|
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
|
-
|
|
600
|
-
export const notificationSubscriptions = defineSubscription({
|
|
601
|
-
notificationAdded: {
|
|
602
|
-
subscribe: () => pubsub.asyncIterator('NOTIFICATION_ADDED'),
|
|
603
|
-
},
|
|
604
|
-
})
|
|
605
|
-
```
|
|
368
|
+
## 🛠️ Development
|
|
606
369
|
|
|
607
|
-
|
|
370
|
+
```bash
|
|
371
|
+
# Install dependencies
|
|
372
|
+
pnpm install
|
|
608
373
|
|
|
609
|
-
|
|
610
|
-
|
|
374
|
+
# Build module
|
|
375
|
+
pnpm build
|
|
611
376
|
|
|
612
|
-
|
|
613
|
-
|
|
377
|
+
# Watch mode
|
|
378
|
+
pnpm dev
|
|
614
379
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
626
|
-
|
|
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
|
-
|
|
389
|
+
## 💬 Community
|
|
637
390
|
|
|
638
|
-
|
|
639
|
-
|
|
391
|
+
> [!TIP]
|
|
392
|
+
> **Want to contribute?** We believe you can play a role in the growth of this project!
|
|
640
393
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
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
|
-
|
|
695
|
-
|
|
696
|
-
|
|
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
|
-
|
|
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
|