T
TanStack7mo ago
optimistic-gold

Is there a typesafe way to build a path to string?

Question I'm using Tanstack Router and Tanstack Start and I'm wondering if there's a way to do something like:
const path = buildPath({ to: "/$lang/posts/$id", params: { lang, id }});
const path = buildPath({ to: "/$lang/posts/$id", params: { lang, id }});
so that path is the resolved string and buildPath only accepts type safe to and params. Specific use case I'm using OAuth as an authentication method and I have an api route at /api/auth/google which accepts a redirect query param so that once the authentication is complete the flow ends by redirecting to redirect and I'd like to pass a valid path to this redirect query param like so:
const path = buildPath({ to: "/$lang/posts/$id", params: { lang, id }});

// ...

<a href={`/api/auth/google?redirect=${encodeURIComponent(path)}`}>...</a>
const path = buildPath({ to: "/$lang/posts/$id", params: { lang, id }});

// ...

<a href={`/api/auth/google?redirect=${encodeURIComponent(path)}`}>...</a>
27 Replies
correct-apricot
correct-apricot7mo ago
router.buildLocation(...)
optimistic-gold
optimistic-goldOP7mo ago
You are the MVP 💪
correct-apricot
correct-apricot7mo ago
btw we will be making api routes possible anywhere, not just under /api which also means, we can make API routes for GET appear in the to of Link
optimistic-gold
optimistic-goldOP7mo ago
I think I might actually be in love 💕
correct-apricot
correct-apricot7mo ago
this will take some more time, but just so you know your feedback was well received thanks for making us make start better!
optimistic-gold
optimistic-goldOP7mo ago
Thank you very much 🙏 @Manuel Schiller By any chance is there a similar method (router.buildLocation) that can be used within a loader?
correct-apricot
correct-apricot7mo ago
you can use that inside a loader does that not work?
optimistic-gold
optimistic-goldOP7mo ago
I don't seem to have access to router in the loader There's a route but doesn't expose that method
correct-apricot
correct-apricot7mo ago
you would need to import it but that does not work on start i see why do you need this in the loader? maybe there is another way to get to the same result
optimistic-gold
optimistic-goldOP7mo ago
I realised that if I want a requireAuthenticated kind of utility then I need to make sure I queryClient.ensureQueryData the getViewer query and that can only be done in the loader AFAIK. Overall I'm trying to create an easy to import and use "requireAuthenticated" guard that checks if the getViewer query has a user and if not redirects to /sign-in?redirect=[current path] Per route
correct-apricot
correct-apricot7mo ago
and you need location building for the current path?
optimistic-gold
optimistic-goldOP7mo ago
that's a good question actually I don't need it in the loader because I can just throw redirect(...)
correct-apricot
correct-apricot7mo ago
yes
optimistic-gold
optimistic-goldOP7mo ago
Is this the recommended way to have such a guard?
correct-apricot
correct-apricot7mo ago
dont know what exactly you are building here but, usually those checks are done in beforeLoad as they are executed serially instead of in parallel as loaders
optimistic-gold
optimistic-goldOP7mo ago
loader: async ({ context, route }) => {
console.log({ path: route.path });
await authenticatedRoute(context.queryClient, route.path);
},
loader: async ({ context, route }) => {
console.log({ path: route.path });
await authenticatedRoute(context.queryClient, route.path);
},
and
import { QueryClient } from "@tanstack/react-query";
import { redirect } from "@tanstack/react-router";
import { getViewerQuery } from "~/client/queries/use-viewer";
import { getLanguage } from "~/server/lib/session";

export const authenticatedRoute = async (
queryClient: QueryClient,
currentPath: string
) => {
const viewer = await queryClient.ensureQueryData(getViewerQuery);
if (!viewer.user) {
const lang = getLanguage();
throw redirect({
to: "/$lang/sign-in",
params: { lang },
search: { redirect: currentPath },
});
}
return viewer;
};
import { QueryClient } from "@tanstack/react-query";
import { redirect } from "@tanstack/react-router";
import { getViewerQuery } from "~/client/queries/use-viewer";
import { getLanguage } from "~/server/lib/session";

export const authenticatedRoute = async (
queryClient: QueryClient,
currentPath: string
) => {
const viewer = await queryClient.ensureQueryData(getViewerQuery);
if (!viewer.user) {
const lang = getLanguage();
throw redirect({
to: "/$lang/sign-in",
params: { lang },
search: { redirect: currentPath },
});
}
return viewer;
};
correct-apricot
correct-apricot7mo ago
you should do that in beforeLoad
optimistic-gold
optimistic-goldOP7mo ago
I see
correct-apricot
correct-apricot7mo ago
but aside from that, it's the same
optimistic-gold
optimistic-goldOP7mo ago
but in the before load I don't have access to route
correct-apricot
correct-apricot7mo ago
you dont?
optimistic-gold
optimistic-goldOP7mo ago
No description
optimistic-gold
optimistic-goldOP7mo ago
And nothign that starts with rout
correct-apricot
correct-apricot7mo ago
you dont need the route though? you just need location
optimistic-gold
optimistic-goldOP7mo ago
Oh yeah that's available Nice Thanks again 🙏
extended-salmon
extended-salmon3mo ago
I have a similar problem but for some reason it appears that router.buildLocation to/from options are not type safe? Is that correct?
correct-apricot
correct-apricot3mo ago
are you using a recent version of router? we had a regression but that was fixed

Did you find this page helpful?