T
TanStack9mo ago
national-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
unwilling-turquoise
unwilling-turquoise9mo ago
router.buildLocation(...)
national-gold
national-goldOP9mo ago
You are the MVP 💪
unwilling-turquoise
unwilling-turquoise9mo 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
national-gold
national-goldOP9mo ago
I think I might actually be in love 💕
unwilling-turquoise
unwilling-turquoise9mo ago
this will take some more time, but just so you know your feedback was well received thanks for making us make start better!
national-gold
national-goldOP9mo ago
Thank you very much 🙏 @Manuel Schiller By any chance is there a similar method (router.buildLocation) that can be used within a loader?
unwilling-turquoise
unwilling-turquoise9mo ago
you can use that inside a loader does that not work?
national-gold
national-goldOP9mo ago
I don't seem to have access to router in the loader There's a route but doesn't expose that method
unwilling-turquoise
unwilling-turquoise9mo 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
national-gold
national-goldOP9mo 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
unwilling-turquoise
unwilling-turquoise9mo ago
and you need location building for the current path?
national-gold
national-goldOP9mo ago
that's a good question actually I don't need it in the loader because I can just throw redirect(...)
unwilling-turquoise
unwilling-turquoise9mo ago
yes
national-gold
national-goldOP9mo ago
Is this the recommended way to have such a guard?
unwilling-turquoise
unwilling-turquoise9mo 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
national-gold
national-goldOP9mo 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;
};
unwilling-turquoise
unwilling-turquoise9mo ago
you should do that in beforeLoad
national-gold
national-goldOP9mo ago
I see
unwilling-turquoise
unwilling-turquoise9mo ago
but aside from that, it's the same
national-gold
national-goldOP9mo ago
but in the before load I don't have access to route
unwilling-turquoise
unwilling-turquoise9mo ago
you dont?
national-gold
national-goldOP9mo ago
No description
national-gold
national-goldOP9mo ago
And nothign that starts with rout
unwilling-turquoise
unwilling-turquoise9mo ago
you dont need the route though? you just need location
national-gold
national-goldOP9mo ago
Oh yeah that's available Nice Thanks again 🙏
correct-apricot
correct-apricot6mo 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?
unwilling-turquoise
unwilling-turquoise6mo ago
are you using a recent version of router? we had a regression but that was fixed

Did you find this page helpful?