T
TanStack3mo ago
exotic-emerald

Guaranteed way to use loader only from server

So, I have the following situation: we have a c# backend that provides API endpoints protected by access tokens, and custom oidc provider (all inhouse services) On the tanstack start side, better-auth is handling the auth and access token acquiring and kubb is generating fetch client for c# services from openAPI schema. Now, from what I've tried, calling the loader function on the route is fetching data on the server on first load, but then on subsequent loads (navigation back and forth) it's calling the loader function on the client. This is not what we want as we do not want to expose an access token or API url to the client. The only guaranteed way was to wrap the API call generated by kubb in the server function that gets called only on the server. But then invalidation of the query for the route becomes router invalidation? This effectively puts tanstack query out of picture and we should probably stick with the tanstack server functions just calling the kubb generated api functions, right?
4 Replies
extended-salmon
extended-salmon3mo ago
Using Server Functions alongside TanStack Query is fully compatible: Server Functions keep tokens and service URLs on the server, while TanStack Query still drives data fetching, caching, revalidation, and mutations on the client via RPC-style calls to those Server Functions.
exotic-emerald
exotic-emeraldOP3mo ago
Yes I get you. I should probably be more specific, obviosly, server fn are solution, but I would have to make out setup little different. Currently, kub is doing this: create functions that return options for Tanstack query calls that calls a singular axios instance with some premade options (base url, custom headers, etc). Now this would have to be replaced with something like this:
export const fetchPosts = createServerFn({ method: 'GET' }).handler(
async () => {
console.info('Fetching posts...')
return axios
.head(env.API_URL, {
headers: {
"Bearer": env.API_TOKEN,
}
})
.get<Array<PostType>>('/posts')
.then((r) => r.data.slice(0, 10))
},
)


export const postsQueryOptions = () =>
queryOptions({
queryKey: ['posts'],
queryFn: () => fetchPosts(),
})
export const fetchPosts = createServerFn({ method: 'GET' }).handler(
async () => {
console.info('Fetching posts...')
return axios
.head(env.API_URL, {
headers: {
"Bearer": env.API_TOKEN,
}
})
.get<Array<PostType>>('/posts')
.then((r) => r.data.slice(0, 10))
},
)


export const postsQueryOptions = () =>
queryOptions({
queryKey: ['posts'],
queryFn: () => fetchPosts(),
})
that would be generated from the kubb. Am I on the right track?
extended-salmon
extended-salmon3mo ago
I think so
deep-jade
deep-jade3mo ago
That seems reasonable. I'd solve the problem like this at least.

Did you find this page helpful?