Skip to content

Commit e9001b2

Browse files
feat: enhance GraphQL SDK with execution result types and code (#15)
* feat: enhance GraphQL SDK with execution result types and code generation configuration * feat: update client type generation to include sdkConfig in generateClientTypes function
1 parent f18f8df commit e9001b2

File tree

5 files changed

+57
-48
lines changed

5 files changed

+57
-48
lines changed

playground-nuxt/app/graphql/sdk.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
/* prettier-ignore */
66
import type * as Types from '#graphql/client';
77

8+
import type { ExecutionResult } from 'graphql';
89

910
export const CreateUserDocument = /*#__PURE__*/ `
1011
mutation CreateUser($input: CreateUserInput!) {
@@ -51,23 +52,23 @@ export const GetUserDocument = /*#__PURE__*/ `
5152
}
5253
}
5354
`;
54-
export type Requester<C = {}> = <R, V>(doc: string, vars?: V, options?: C) => Promise<R> | AsyncIterable<R>
55-
export function getSdk<C>(requester: Requester<C>) {
55+
export type Requester<C = {}, E = unknown> = <R, V>(doc: string, vars?: V, options?: C) => Promise<ExecutionResult<R, E>> | AsyncIterable<ExecutionResult<R, E>>
56+
export function getSdk<C, E>(requester: Requester<C, E>) {
5657
return {
57-
CreateUser(variables: Types.CreateUserMutationVariables, options?: C): Promise<Types.CreateUserMutation> {
58-
return requester<Types.CreateUserMutation, Types.CreateUserMutationVariables>(CreateUserDocument, variables, options) as Promise<Types.CreateUserMutation>;
58+
CreateUser(variables: Types.CreateUserMutationVariables, options?: C): Promise<ExecutionResult<Types.CreateUserMutation, E>> {
59+
return requester<Types.CreateUserMutation, Types.CreateUserMutationVariables>(CreateUserDocument, variables, options) as Promise<ExecutionResult<Types.CreateUserMutation, E>>;
5960
},
60-
UpdateUser(variables: Types.UpdateUserMutationVariables, options?: C): Promise<Types.UpdateUserMutation> {
61-
return requester<Types.UpdateUserMutation, Types.UpdateUserMutationVariables>(UpdateUserDocument, variables, options) as Promise<Types.UpdateUserMutation>;
61+
UpdateUser(variables: Types.UpdateUserMutationVariables, options?: C): Promise<ExecutionResult<Types.UpdateUserMutation, E>> {
62+
return requester<Types.UpdateUserMutation, Types.UpdateUserMutationVariables>(UpdateUserDocument, variables, options) as Promise<ExecutionResult<Types.UpdateUserMutation, E>>;
6263
},
63-
DeleteUser(variables: Types.DeleteUserMutationVariables, options?: C): Promise<Types.DeleteUserMutation> {
64-
return requester<Types.DeleteUserMutation, Types.DeleteUserMutationVariables>(DeleteUserDocument, variables, options) as Promise<Types.DeleteUserMutation>;
64+
DeleteUser(variables: Types.DeleteUserMutationVariables, options?: C): Promise<ExecutionResult<Types.DeleteUserMutation, E>> {
65+
return requester<Types.DeleteUserMutation, Types.DeleteUserMutationVariables>(DeleteUserDocument, variables, options) as Promise<ExecutionResult<Types.DeleteUserMutation, E>>;
6566
},
66-
GetUsers(variables?: Types.GetUsersQueryVariables, options?: C): Promise<Types.GetUsersQuery> {
67-
return requester<Types.GetUsersQuery, Types.GetUsersQueryVariables>(GetUsersDocument, variables, options) as Promise<Types.GetUsersQuery>;
67+
GetUsers(variables?: Types.GetUsersQueryVariables, options?: C): Promise<ExecutionResult<Types.GetUsersQuery, E>> {
68+
return requester<Types.GetUsersQuery, Types.GetUsersQueryVariables>(GetUsersDocument, variables, options) as Promise<ExecutionResult<Types.GetUsersQuery, E>>;
6869
},
69-
GetUser(variables: Types.GetUserQueryVariables, options?: C): Promise<Types.GetUserQuery> {
70-
return requester<Types.GetUserQuery, Types.GetUserQueryVariables>(GetUserDocument, variables, options) as Promise<Types.GetUserQuery>;
70+
GetUser(variables: Types.GetUserQueryVariables, options?: C): Promise<ExecutionResult<Types.GetUserQuery, E>> {
71+
return requester<Types.GetUserQuery, Types.GetUserQueryVariables>(GetUserDocument, variables, options) as Promise<ExecutionResult<Types.GetUserQuery, E>>;
7172
}
7273
};
7374
}

playground/graphql/sdk.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,18 @@
55
/* prettier-ignore */
66
import type * as Types from '#graphql/client';
77

8-
export type GetUsersQueryVariables = Types.Exact<{ [key: string]: never; }>;
9-
10-
11-
export type GetUsersQuery = { __typename?: 'Query', hello: string };
12-
8+
import type { ExecutionResult } from 'graphql';
139

1410
export const GetUsersDocument = /*#__PURE__*/ `
1511
query GetUsers {
1612
hello
1713
}
1814
`;
19-
export type Requester<C = {}> = <R, V>(doc: string, vars?: V, options?: C) => Promise<R> | AsyncIterable<R>
20-
export function getSdk<C>(requester: Requester<C>) {
15+
export type Requester<C = {}, E = unknown> = <R, V>(doc: string, vars?: V, options?: C) => Promise<ExecutionResult<R, E>> | AsyncIterable<ExecutionResult<R, E>>
16+
export function getSdk<C, E>(requester: Requester<C, E>) {
2117
return {
22-
GetUsers(variables?: Types.GetUsersQueryVariables, options?: C): Promise<Types.GetUsersQuery> {
23-
return requester<Types.GetUsersQuery, Types.GetUsersQueryVariables>(GetUsersDocument, variables, options) as Promise<Types.GetUsersQuery>;
18+
GetUsers(variables?: Types.GetUsersQueryVariables, options?: C): Promise<ExecutionResult<Types.GetUsersQuery, E>> {
19+
return requester<Types.GetUsersQuery, Types.GetUsersQueryVariables>(GetUsersDocument, variables, options) as Promise<ExecutionResult<Types.GetUsersQuery, E>>;
2420
}
2521
};
2622
}

src/types/index.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { TypeScriptPluginConfig } from '@graphql-codegen/typescript'
2+
import type { plugin as typescriptGenericSdk } from '@graphql-codegen/typescript-generic-sdk'
23
import type { TypeScriptDocumentsPluginConfig } from '@graphql-codegen/typescript-operations'
34
import type { TypeScriptResolversPluginConfig } from '@graphql-codegen/typescript-resolvers'
45
import type { IResolvers } from '@graphql-tools/utils'
@@ -8,6 +9,19 @@ export type { StandardSchemaV1 } from './standard-schema'
89

910
export type CodegenServerConfig = TypeScriptPluginConfig & TypeScriptResolversPluginConfig
1011

12+
// CODEGEN
13+
type DocumentModeConfig = Pick<Parameters<typeof typescriptGenericSdk>[2], 'documentMode'>
14+
type DocumentModeEnum = NonNullable<DocumentModeConfig['documentMode']>
15+
type DocumentModeType = `${DocumentModeEnum}`
16+
17+
export type GenericSdkConfig = Omit<Parameters<typeof typescriptGenericSdk>[2], 'documentMode'> & {
18+
documentMode?: DocumentModeType
19+
}
20+
21+
export type CodegenClientConfig = TypeScriptPluginConfig & TypeScriptDocumentsPluginConfig & {
22+
endpoint?: string
23+
}
24+
1125
interface IESMImport {
1226
name: string
1327
as?: string
@@ -53,11 +67,6 @@ declare module 'nitropack' {
5367
}
5468
}
5569

56-
export interface CodegenClientConfig extends TypeScriptPluginConfig, TypeScriptDocumentsPluginConfig {
57-
endpoint?: string
58-
documentMode?: 'string' | 'graphQLTag' | 'documentNode' | 'documentNodeImportFragments' | 'external'
59-
}
60-
6170
export interface NitroGraphQLOptions {
6271
framework: 'graphql-yoga' | 'apollo-server'
6372
endpoint?: {
@@ -75,5 +84,6 @@ export interface NitroGraphQLOptions {
7584
codegen?: {
7685
server?: CodegenServerConfig
7786
client?: CodegenClientConfig
87+
clientSDK?: GenericSdkConfig
7888
}
7989
}

src/utils/client-codegen.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { LoadSchemaOptions, UnnormalizedTypeDefPointer } from '@graphql-tools/load'
22
import type { Source } from '@graphql-tools/utils'
33
import type { GraphQLSchema } from 'graphql'
4-
import type { CodegenClientConfig } from '../types'
4+
import type { CodegenClientConfig, GenericSdkConfig } from '../types'
55
import { codegen } from '@graphql-codegen/core'
66
import { preset } from '@graphql-codegen/import-types-preset'
77
import { plugin as typescriptPlugin } from '@graphql-codegen/typescript'
@@ -101,6 +101,7 @@ export async function generateClientTypes(
101101
schema: GraphQLSchema,
102102
docs: Source[],
103103
config: CodegenClientConfig = {},
104+
sdkConfig: GenericSdkConfig = {},
104105
outputPath?: string,
105106
) {
106107
if (docs.length === 0) {
@@ -111,7 +112,6 @@ export async function generateClientTypes(
111112
consola.info(`[graphql] Found ${docs.length} client GraphQL documents`)
112113

113114
const defaultConfig: CodegenClientConfig = {
114-
documentMode: 'string',
115115
emitLegacyCommonJSImports: false,
116116
useTypeImports: true,
117117
enumsAsTypes: true,
@@ -129,6 +129,25 @@ export async function generateClientTypes(
129129

130130
const mergedConfig = defu(config, defaultConfig)
131131

132+
const defaultSdkConfig: GenericSdkConfig = {
133+
documentMode: 'string',
134+
pureMagicComment: true,
135+
strictScalars: true,
136+
useTypeImports: true,
137+
dedupeOperationSuffix: true,
138+
rawRequest: true,
139+
140+
scalars: {
141+
DateTime: 'Date',
142+
JSON: 'any',
143+
UUID: 'string',
144+
NonEmptyString: 'string',
145+
Currency: 'string',
146+
},
147+
}
148+
149+
const mergedSdkConfig = defu(sdkConfig, defaultSdkConfig)
150+
132151
try {
133152
const output = await codegen({
134153
filename: outputPath || 'client-types.generated.ts',
@@ -151,30 +170,13 @@ export async function generateClientTypes(
151170
baseOutputDir: outputPath || 'client-types.generated.ts',
152171
schema: parse(printSchemaWithDirectives(schema)),
153172
documents: [...docs],
154-
config: {
155-
fetcher: 'function',
156-
documentMode: 'string',
157-
pureMagicComment: true,
158-
strictScalars: true,
159-
avoidOptionals: true,
160-
useTypeImports: true,
161-
dedupeOperationSuffix: true,
162-
exportFragmentSpreadSubTypes: true,
163-
enumsAsTypes: true,
164-
scalars: {
165-
DateTime: 'Date',
166-
JSON: 'any',
167-
UUID: 'string',
168-
NonEmptyString: 'string',
169-
Currency: 'string',
170-
},
171-
},
173+
config: mergedSdkConfig,
172174
presetConfig: {
173175
typesPath: '#graphql/client',
174176
},
175177
plugins: [
176178
{ pluginContent: {} },
177-
{ typescriptGenericSdk: { rawRequest: false } },
179+
{ typescriptGenericSdk: { } },
178180
],
179181
pluginMap: {
180182
pluginContent: { plugin: pluginContent },

src/utils/type-generation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export async function clientTypeGeneration(
9595
const graphqlString = readFileSync(schemaFilePath, 'utf-8')
9696
const schema = buildSchema(graphqlString)
9797

98-
const types = await generateClientTypes(schema, loadDocs, nitro.options.graphql?.codegen?.client ?? {})
98+
const types = await generateClientTypes(schema, loadDocs, nitro.options.graphql?.codegen?.client ?? {}, nitro.options.graphql?.codegen?.clientSDK ?? {})
9999
if (types === false) {
100100
return
101101
}

0 commit comments

Comments
 (0)