W
Wasp•2mo ago
NEROX

Navigating with /names/ instead /ids/

How can I change my navigation so instead the final slug is /subject/maths/grades instead of /subject/31c984d4-686d-4c3e-97dc-94dbd2bc5a58/grades Information to note, names can be repeated in the db so the key identifier is still the id but I want only the name.
6 Replies
kapa.ai
kapa.ai•2mo ago
Hi @NEROX. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To achieve navigation with names instead of IDs in your Wasp application, you can use a combination of route parameters and data fetching. Here's how you can approach this: 1. Define a route with a name parameter: In your main.wasp file, define a route that uses the subject name instead of ID:
route SubjectGradesRoute { path: "/subject/:name/grades", to: SubjectGradesPage }
page SubjectGradesPage {
component: import { SubjectGradesPage } from "@src/SubjectGradesPage"
}
route SubjectGradesRoute { path: "/subject/:name/grades", to: SubjectGradesPage }
page SubjectGradesPage {
component: import { SubjectGradesPage } from "@src/SubjectGradesPage"
}
This sets up a route that will match paths like /subject/maths/grades Wasp Docs: Adding a Second Page (https://wasp-lang.dev/docs/tutorial/pages#adding-a-second-page). 2. In your React component, use the name parameter to fetch the correct subject:
import { useParams } from 'react-router-dom'
import { useQuery } from '@wasp/queries'
import { getSubjectByName } from '@wasp/queries/getSubjectByName'

export function SubjectGradesPage() {
const { name } = useParams<{ name: string }>()
const { data: subject, isLoading, error } = useQuery(getSubjectByName, { name })

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!subject) return <div>Subject not found</div>

return (
<div>
<h1>{subject.name} Grades</h1>
{/* Display grades here */}
</div>
)
}
import { useParams } from 'react-router-dom'
import { useQuery } from '@wasp/queries'
import { getSubjectByName } from '@wasp/queries/getSubjectByName'

export function SubjectGradesPage() {
const { name } = useParams<{ name: string }>()
const { data: subject, isLoading, error } = useQuery(getSubjectByName, { name })

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!subject) return <div>Subject not found</div>

return (
<div>
<h1>{subject.name} Grades</h1>
{/* Display grades here */}
</div>
)
}
3. Create a query to fetch the subject by name: In your src/server/queries.ts file:
import { HttpError } from '@wasp/middleware'

export const getSubjectByName = async ({ name }, context) => {
const subject = await context.entities.Subject.findFirst({
where: { name: name }
})

if (!subject) {
throw new HttpError(404, 'Subject not found')
}

return subject
}
import { HttpError } from '@wasp/middleware'

export const getSubjectByName = async ({ name }, context) => {
const subject = await context.entities.Subject.findFirst({
where: { name: name }
})

if (!subject) {
throw new HttpError(404, 'Subject not found')
}

return subject
}
4. When creating links to subject pages, use the subject name:
import { Link } from 'wasp/client/router'

function SubjectList({ subjects }) {
return (
<ul>
{subjects.map((subject) => (
<li key={subject.id}>
<Link
to="/subject/:name/grades"
params={{ name: subject.name }}
>
{subject.name}
</Link>
</li>
))}
</ul>
)
}
import { Link } from 'wasp/client/router'

function SubjectList({ subjects }) {
return (
<ul>
{subjects.map((subject) => (
<li key={subject.id}>
<Link
to="/subject/:name/grades"
params={{ name: subject.name }}
>
{subject.name}
</Link>
</li>
))}
</ul>
)
}
This approach allows you to use names in the URL while still using the ID as the key identifier in your database. However, keep in mind that if subject names are not unique, this could lead to ambiguity. You might need to implement additional logic to handle cases where multiple subjects have the same name. Also, remember that using names in URLs can make them more susceptible to changes if the names are updated in the database. You might want to consider using a slug (a URL-friendly version of the name) instead of the raw name for more stability. Wasp Docs: Type-Safe Links (https://wasp-lang.dev/docs/advanced/links) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
miho
miho•2mo ago
The route is /subject/:something/grades that :something can be any string - so if you build you URLs to include maths instead of an ID - it will work - but you'll need to then fetch what you need by the name instead the ID. There are no limitations here AFAIK 🙂
NEROX
NEROXOP•2mo ago
Acomplished! Thanks @miho for the short solution :D @miho What I did wrong? https://toograded.com/gradebook-online If you register with new account, all the data appears from any account :laughboi: Also you can modify it. I mean, I DIDN'T WANTED TO CREATE A COLLECTIVE GRADEBOOK :laughboi: :laughboi: :laughboi: :laughboi: :laughboi: ps: all it's test data, so you can also try to ad things.
miho
miho•2mo ago
In your Prisma queries, it's key to put the where blocks that filter the data per user 🙂 it doesn't happen automatically Smth like this
const posts = await prisma.post.findMany({
where: {
userId: context.user.id
},
include: {
comments: true,
categories: true
}
})
const posts = await prisma.post.findMany({
where: {
userId: context.user.id
},
include: {
comments: true,
categories: true
}
})
VS
VS•2mo ago
Also to add maybe some things like these as well if (!post) { throw new HttpError(404, 'Exam not found'); } // Check if the user has permission to view this exam if (exam.userId !== context.user?.id ) { if (!token) { throw new HttpError(403, 'You do not have permission to view this post'); } } return post; };
NEROX
NEROXOP•2mo ago
✅ Solved, thank you guyz!!!:boi:
Want results from more Discord servers?
Add your server