Skip to content
Chapter 33Lesson 6

Quiz - The request surface

Quiz progress

0 / 0

A teammate ships an auth gate in proxy.ts. It reads the session cookie, verifies it against the database, and bounces signed-out users — and they’ve decided that since the proxy now does the real check, the routes themselves no longer need one. What’s wrong with this plan? Select all that apply.

A database read in the proxy runs on every matched request, multiplying a cost you’d otherwise pay once in the route — the classic “why did every page get slow” regression.
Excluding a path from the matcher (or a refactor that does so) silently drops proxy coverage on Server Action POSTs to that path, so a proxy-only gate can leave a hole nothing flags.
It’s the right call: centralizing the authoritative check in one file is exactly what proxy.ts is for, and duplicating it in every route is wasteful.

A Server Component reads (await headers()).get('x-forwarded-for') to get the client IP, and another component reads a custom x-user-role header to decide whether to show an admin panel. Which read is the dangerous one, and why?

The x-user-role read — it makes an authorization decision from a header, which any client can forge. Identity and permission come from the verified session, never a raw header.
The x-forwarded-for read — IP addresses are personal data, so reading one without consent is the real risk; the role header is fine because the app set it.
Neither is dangerous — headers arriving at a Server Component have already passed through the platform, so they can be trusted for any decision.

Your SaaS permanently moves /account to /settings, and separately bounces already-logged-in users away from /login. A reviewer says “just use NextResponse.redirect(url) for both and you’re done.” What does that miss?

The /account move should be a 308 (permanent) but redirect() defaults to 307; and the /login bounce should stay 307 because it depends on the user’s session — a 308 there gets cached as “never visit /login,” wrong once they log out.
Both belong in next.config.ts instead, because any redirect is cheaper at the CDN edge regardless of whether it reads the request.
Nothing — NextResponse.redirect(url) already sends a permanent redirect by default, which is correct for both cases.

Building an invoice list, you wire the status filter into useState, refetch in a useEffect, and render. It works on your screen. Why does a senior reach for URL state instead?

The filter is state a user expects to survive a refresh and travel in a shared link — that belongs in the URL, where a Server Component reads it directly with no client state, no effect, and no fetch waterfall.
useState can’t hold a filter value reliably across re-renders, so the URL is the only place the value stays stable.
URL state is faster only because the browser caches query strings; functionally the two approaches are equivalent.

A 'use client' filter chip needs to show whether it’s the active filter and, on click, change the URL to its status while keeping the existing ?sort and ?cursor params. Which approach is right?

Take the active status as a prop the server already resolved (no hook to read it), and on click seed a new URLSearchParams from the current query, set the one key, and router.replace(..., { scroll: false }).
Read the active status with useSearchParams for live accuracy, and on click router.push('?status=paid') so the back button can step through each filter.
Read the active status with useSearchParams, and on click router.replace('?status=paid') — the shortest correct write.

Quiz complete

Score by topic