Add Filtering and Details
Imagine you run a cooking school with three courses and hundreds of feedback entries. Someone asks, "What are people saying about the knife skills course?" You wouldn't hand them every piece of feedback you've ever received and say, "It's in there somewhere." You'd filter.
We need two things: query parameters on the list endpoint to narrow results, and a way to fetch a single entry by its ID.
Outcome
Add query param filtering to GET /api/feedback and create a GET /api/feedback/:id route.
Fast Track
- Add
courseSlug,lessonSlug, andminRatingquery param support to the GET handler - Implement the GET handler in
app/api/feedback/[id]/route.ts - Return 404 for unknown IDs
Hands-on exercise
Part 1: Query parameters
Update the existing GET handler in app/api/feedback/route.ts to support three optional query parameters:
courseSlug: filter entries wherecourseSlugmatches exactlylessonSlug: filter entries wherelessonSlugmatches exactlyminRating: filter entries whereratingis greater than or equal to the value
Pull these from request.nextUrl.searchParams. Each filter is optional. If none are provided, return everything (the current behavior). If multiple are provided, apply them all.
const { searchParams } = request.nextUrl;
const courseSlug = searchParams.get("courseSlug");Part 2: Single feedback by ID
Open app/api/feedback/[id]/route.ts. The starter has this file with a stub handler. The brackets in [id] make this a dynamic segment. Next.js passes the value through the params prop.
In Next.js 16, params is a Promise. You need to await it:
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
// ...
}Look up the feedback using getFeedbackById. If it doesn't exist, return a 404 with a helpful error message that includes the ID the caller asked for. This matters more than you might think. When an agent gets a 404, the error message is how it decides what to try next.
If you forget to await params, you'll get a TypeScript error about id being a Promise. This is a common stumble in Next.js 16 since params changed from a plain object to a Promise.
Query parameters are always strings. If you compare fb.rating >= minRating without parsing, you're doing string comparison, not numeric comparison. "5" >= "4" happens to work, but "5" >= "10" does not. Always use parseInt(minRating, 10) before comparing.
In Next.js 16, params is async. If your TypeScript shows an error like "Property 'id' does not exist on type 'Promise'", you forgot to await params. The signature needs { params }: { params: Promise<{ id: string }> } and you must const { id } = await params before using it.
Check that your filter logic uses strict equality (===) for slug comparisons and >= with the parsed integer for minRating. A common mistake is checking if (courseSlug) but then forgetting to actually filter inside the block.
Try It
Filter by course:
curl "http://localhost:3000/api/feedback?courseSlug=knife-skills"Should return only the knife-skills entries (5 in the seed data).
Filter by minimum rating:
curl "http://localhost:3000/api/feedback?minRating=5"Should return only 5-star entries.
Combine filters:
curl "http://localhost:3000/api/feedback?courseSlug=bread-baking&minRating=4"Only bread-baking entries rated 4 or above.
Fetch a single entry:
curl http://localhost:3000/api/feedback/fb-001{
"id": "fb-001",
"courseSlug": "knife-skills",
"lessonSlug": "the-claw-grip",
"rating": 5,
"comment": "Finally understand why my onion cuts were uneven. The claw grip changed everything.",
"author": "Priya Sharma",
"createdAt": "2026-03-01T10:30:00Z"
}Fetch a nonexistent entry:
curl http://localhost:3000/api/feedback/fb-999{
"error": "Feedback with id \"fb-999\" not found"
}Back to our cooking school. Instead of dumping every piece of feedback on someone's desk, we can now hand them exactly what they asked for. Knife skills feedback? Here. Only the top-rated stuff? Done. One specific entry from that student who had a lot of feelings about sourdough? Got it.
Commit
git add -A && git commit -m "feat(api): add query param filtering and single-feedback route"Done-When
GET /api/feedback?courseSlug=knife-skillsreturns only knife-skills feedbackGET /api/feedback?minRating=5returns only 5-star entries- Multiple query params combine (AND logic)
GET /api/feedback/fb-001returns a single entryGET /api/feedback/fb-999returns 404 with an error message that includes the ID
Solution
import { NextRequest, NextResponse } from "next/server";
import { getAllFeedback, addFeedback } from "@/lib/data";
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const courseSlug = searchParams.get("courseSlug");
const lessonSlug = searchParams.get("lessonSlug");
const minRating = searchParams.get("minRating");
let feedback = await getAllFeedback();
if (courseSlug) {
feedback = feedback.filter((fb) => fb.courseSlug === courseSlug);
}
if (lessonSlug) {
feedback = feedback.filter((fb) => fb.lessonSlug === lessonSlug);
}
if (minRating) {
const min = parseInt(minRating, 10);
feedback = feedback.filter((fb) => fb.rating >= min);
}
return NextResponse.json(feedback);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const { courseSlug, lessonSlug, rating, comment, author } = body;
if (!courseSlug || !lessonSlug || rating == null || !comment || !author) {
return NextResponse.json(
{ error: "Missing required fields: courseSlug, lessonSlug, rating, comment, author" },
{ status: 400 }
);
}
if (typeof rating !== "number" || rating < 1 || rating > 5) {
return NextResponse.json(
{ error: "Rating must be a number between 1 and 5" },
{ status: 400 }
);
}
const entry = await addFeedback({ courseSlug, lessonSlug, rating, comment, author });
return NextResponse.json(entry, { status: 201 });
}import { NextRequest, NextResponse } from "next/server";
import { getFeedbackById } from "@/lib/data";
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const feedback = await getFeedbackById(id);
if (!feedback) {
return NextResponse.json(
{ error: `Feedback with id "${id}" not found` },
{ status: 404 }
);
}
return NextResponse.json(feedback);
}Was this helpful?