Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom fetch function #1563

Closed
kansson opened this issue Mar 15, 2023 · 10 comments
Closed

Custom fetch function #1563

kansson opened this issue Mar 15, 2023 · 10 comments

Comments

@kansson
Copy link

kansson commented Mar 15, 2023

Hello!
This issue is related to #1185.
In SvelteKit you need to use their custom fetch function when making http calls inside load functions. See https://kit.svelte.dev/docs/load#making-fetch-requests and https://kit.svelte.dev/docs/web-standards#fetch-apis.
One solution would be to simply allow passing a custom fetch function like we already do for fetchOptions.

@vicary
Copy link
Member

vicary commented Mar 15, 2023

Hey there, I am not really familiar with SvelteKit, is there fetch API injected and replaced the native fetch?

Our generated client allows you to write your own query fetcher, does that serves that Svelte needs?

@kansson
Copy link
Author

kansson commented Mar 15, 2023

No the fetch function is passed to load functions as a parameter. The native fetch function is not replaced by SvelteKit.
I did modify the generated QueryFetcher and got it working so it does serve the needs for Svelte.
Just thought that this could be simplified by allowing to pass a custom fetch function. TRPC does something similar in their client. https://trpc.io/docs/links/httpLink#httplink-options
Feel free to close if this is out of scope.

@vicary
Copy link
Member

vicary commented Mar 15, 2023

No worries, I don't think it's out of scope. Do you want to pass a fetch impl for each fetch? Because tRPC's httpLink feels like it is defined at top level where your fetch is at component level. Am I understanding it correctly?

@kansson
Copy link
Author

kansson commented Mar 15, 2023

You are right, the fetch would need to be passed with each query. This is just how SvelteKit works and I don't think there is a better solution. The Svelte implementation of TRPC does it that way https://github.com/icflorescu/trpc-sveltekit/blob/main/package/src/client.ts#L9.

@vicary
Copy link
Member

vicary commented Mar 16, 2023

Understood, adding such an option in the useQuery() family is possible. Although we'll have to decide if it's best added in the current version or the next major, will keep you posted.

@kansson
Copy link
Author

kansson commented May 2, 2023

Hi again, came back to this and saw the new updated docs. Looks good!
Tested the new fetch method using resolve and it works great!

This is the custom query fetcher I'm using. Looking forward to seeing the official SvelteKit integration later.

export const gqty = (event: Partial<RequestEvent> & Pick<RequestEvent, 'fetch'>) => {
  const { resolve } = createClient<GeneratedSchema>({
    schema: generatedSchema,
    scalars: scalarsEnumsHash,
    cache,
    fetchOptions: {
      fetcher: async ({ query, variables, operationName }, fetchOptions) => {
        const response = await event.fetch('http://macbook:3005/api/graphql', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            query,
            variables,
            operationName
          }),
          ...fetchOptions
        })

        return await response.json()
      }
    }
  })

  return resolve
}

And then fetching data like this with SSR working as expected.

export const load = async ({ url, ...event }) => {
  const query = url.searchParams.get('query') ?? ''
  const { results } = await gqty(event)(({ query: { search } }) => ({
    results: search({ query }).map((result) => ({ ...result }))
  }))

  return {
    query,
    results,
    deffered: {
      locales: gqty(event)(({ query: { locales } }) =>
        locales.map((locale) => ({
          ...locale
        }))
      )
    }
  }
}

@vicary
Copy link
Member

vicary commented May 2, 2023

@hanssonduck Thanks for trying out the alpha, our internal tests are almost done and we are close to announce a public beta!

Let me leak a little bit of my unreleased plans. There is this extensions parameter which is is rarely exposed by GraphQL clients, but it's there inside graphql.js for library authors for a long time.

I am planning to expose the extensions options in resolve() and useQuery() at some point, so you can wire it up for your own fetcher logics at runtime.

You will be able to do this in the future:

await resolve(
  ({ query }) => ({ locales: query.locales.map((locale) => ({ ...locale })) }),
  {
    extensions: {
      fetch: event.fetch,
    },
  }
);

You can then make your queryFetcher generic again like this:

const queryFetcher = async (
  { query, variables, operationName, extensions },
  fetchOptions
) => {
  const fetchImpl = extensions?.fetch ?? fetch;
  const response = await fetchImpl("http://macbook:3005/api/graphql", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      query,
      variables,
      operationName,
    }),
    ...fetchOptions,
  });

  return await response.json();
};

@kansson
Copy link
Author

kansson commented May 2, 2023

@vicary That seems like a great solution. Looking forward to the alpha version getting stable!

@vicary
Copy link
Member

vicary commented May 3, 2023

@hanssonduck I want to slip this through before alpha ends, you may try latest alpha and let me know how it feels.

@vicary
Copy link
Member

vicary commented Nov 30, 2023

Please feel free to re-open if you think the current approach is not enough for your use case!

@vicary vicary closed this as completed Nov 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants