API Routes & Server Actions
Website Rebuild with Next.js
Chapter 8 · API Routes & Server Actions
This chapter gives the admin a way to actually change something — updatePageTitle, a Server Action, with no auth check yet, deliberately: the security gap gets closed properly in Chapter 9. Every one of this course's own five already-complete siblings built the identical feature, the identical gap, closed the identical way one chapter later — a real, intentional continuity thread running through the whole series, not a coincidence of independent design.
Enabling the Cache Components Model
This unlocks 'use cache', cacheTag, and updateTag — the tools this chapter actually needs to give an admin edit a genuine read-your-writes guarantee.
Caching the Page Lookup
Chapter 3's own route now calls getPageByPath(fullPath) in place of a direct prisma.page.findUnique — the query itself is unchanged, but its result is now cached and taggable.
The Server Action: updatePageTitle
updatePageTitle is fully wired up and genuinely works — anyone who can call it can rename any page on the site, right now, with nothing standing in the way. This is left exactly this way on purpose, matching every sibling course's own identical gap, so Chapter 9 has a real, working mutation to actually secure rather than a hypothetical one.
revalidateTag's New Required Argument, vs. updateTag
revalidateTag marks cached data stale and lets it refresh in the background — the visitor who happens to load the page in the exact next instant might still briefly see the old title. updateTag expires and refreshes the cache within the same request, so the admin who just renamed a page sees the new title immediately on the very next page they load — genuine read-your-writes semantics, and a materially better fit for this specific "I just edited something, show me the result" scenario than what this chapter's own original version had available.
Built-In CSRF Protection — The One Piece Nobody Else Had to Wire Up
Origin header against the deployment's allowed origins before running it, rejecting the call outright on a mismatch. Django needed an explicit {% csrf_token %} in every form. Laravel needed @csrf. Rails needed protect_from_forgery plus form_with's own automatic authenticity token. updatePageTitle above has no equivalent line anywhere — this specific protection is a structural property of what a Server Action is, not something this chapter had to add.
The Same Mutation, Four Structural Answers
| Next.js | Django | Laravel | Rails | |
|---|---|---|---|---|
| Shape | One function — implicit client/server boundary | View function + ModelForm + URL — three explicit pieces | Controller method + FormRequest — a class-based extra layer | Single Controller action, Strong Parameters inline — the leanest of the four |
| Auth gap made visible as | A missing check inside the function body | An absent permission check in the view | authorize() literally returning true | An absent before_action filter |
| CSRF protection | Automatic — built into what a Server Action is | Manual — {% csrf_token %} | Manual — @csrf | Manual — protect_from_forgery + automatic token |
Next.js's own implicit boundary is genuinely a double-edged design: it's what makes updatePageTitle callable like an ordinary function with zero explicit wiring, and it's also exactly why the missing auth check is easy to miss on a casual read — there's no separate file, no visible authorize() method, nothing forcing the question to be asked. Every sibling's own explicit alternative makes the gap structurally harder to overlook, at the cost of more ceremony to write in the first place.
Hands-On Exercises
Build updatePageTitle exactly as written in this chapter, call it against a real page with no authentication in place, and confirm the title actually changes — demonstrating the security gap is real and currently exploitable, not hypothetical.
📄 View solutionExplain why revalidateTag now requires a second argument in Next.js 16, and why this chapter chose updateTag instead of revalidateTag for updatePageTitle specifically — tying the answer to what "read-your-writes" actually means for an admin who just made an edit.
📄 View solutionExplain, in your own words, how a Server Action's built-in Origin-header check achieves the same protective goal as Django's {% csrf_token %}, without any code in updatePageTitle resembling a token at all.
📄 View solutionChapter 8 Quick Reference
updatePageTitle— a working Server Action, deliberately missing its auth check until Chapter 9cacheComponents: true+'use cache'+cacheTag— the current model for taggable, invalidatable server-side cachingupdateTagoverrevalidateTag— genuine read-your-writes for an admin who just made an edit- Automatic CSRF protection — a structural property of Server Actions; the one piece every sibling course had to wire up manually
- Next chapter: Admin Authentication