Skip to content

Instantly share code, notes, and snippets.

@akozhemiakin
Last active July 25, 2023 17:48
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save akozhemiakin/731b0c1e99eb89b01f80f08f9146b6b6 to your computer and use it in GitHub Desktop.
Save akozhemiakin/731b0c1e99eb89b01f80f08f9146b6b6 to your computer and use it in GitHub Desktop.
import { ApolloClient, QueryOptions, MutationOptions } from 'apollo-client';
import { DocumentNode } from 'graphql';
import { getSdk, Requester } from '.generated/schema-typedefs';
import { ApolloRequestError } from './ApolloRequestError';
export type ApolloRequesterOptions<V, R> =
| Omit<QueryOptions<V>, 'variables' | 'query'>
| Omit<MutationOptions<R, V>, 'variables' | 'mutation'>;
const validDocDefOps = ['mutation', 'query', 'subscription'];
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function getSdkApollo<C>(client: ApolloClient<C>) {
const requester: Requester = async <R, V>(
doc: DocumentNode,
variables: V,
options?: ApolloRequesterOptions<V, R>,
): Promise<R> => {
// Valid document should contain *single* query or mutation unless it's has a fragment
if (
doc.definitions.filter(
d =>
d.kind === 'OperationDefinition' &&
validDocDefOps.includes(d.operation),
).length !== 1
) {
throw new Error(
'DocumentNode passed to Apollo Client must contain single query or mutation',
);
}
const definition = doc.definitions[0];
// Valid document should contain *OperationDefinition*
if (definition.kind !== 'OperationDefinition') {
throw new Error(
'DocumentNode passed to Apollo Client must contain single query or mutation',
);
}
switch (definition.operation) {
case 'mutation': {
const response = await client.mutate<R, V>({
mutation: doc,
variables,
...options,
});
if (response.errors) {
throw new ApolloRequestError(response.errors);
}
if (response.data === undefined || response.data === null) {
throw new Error('No data presented in the GraphQL response');
}
return response.data;
}
case 'query': {
const response = await client.query<R, V>({
query: doc,
variables,
...options,
});
if (response.errors) {
throw new ApolloRequestError(response.errors);
}
if (response.data === undefined || response.data === null) {
throw new Error('No data presented in the GraphQL response');
}
return response.data;
}
case 'subscription': {
throw new Error(
'Subscription requests through SDK interface are not supported',
);
}
}
};
return getSdk(requester);
}
export type Sdk = ReturnType<typeof getSdkApollo>;
@davidpurkiss
Copy link

Thanks for this! What does ApolloRequestError look like?

@bakamitai456
Copy link

fetchPolicy of QueryOptions does not compatible with fetchPolicy of MutationOptions . I fixed it by omitting the fetchPolicy of QueryOptions. Are there alternative ways to fix it?

@emdagon
Copy link

emdagon commented Dec 22, 2022

@bakamitai456 I worked around it by doing this:

... (line 42)
case "mutation": {
        const fetchPolicy = options?.fetchPolicy as MutationFetchPolicy;
        const response = await client.mutate<R, V>({
          mutation: doc,
          variables,
          ...options,
          fetchPolicy,
        });
...

Not sure if that's more "elegant", but I prefer it to omitting QueryOptions's fetchPolicy. 😅

@beefancohen
Copy link

i dont think this is working with later versions of typescript. V does not satisfy OperationVariables

@amanptl
Copy link

amanptl commented Jul 19, 2023

@beefancohen Did you find a workaround? I am having the same issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment