Merancang Penangan Rute RESTful dengan API Permintaan Web
Implementasikan penangan GET/POST/PATCH/DELETE menggunakan objek Request dan Response asli serta segmen dinamis.
Merancang Penangan Rute RESTful dengan API Permintaan Web adalah pelajaran Next.js 15 Fullstack (App Router + Server Actions) gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Next.js 15 Fullstack (App Router + Server Actions), dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Next.js 15 Fullstack (App Router + Server Actions) mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
What Route Handlers Are
In the Next.js 15 App Router, a Route Handler is a file named route.ts inside the app directory. It lets you build a REST-style API endpoint without a separate Express server.
- You export an async function named after the HTTP method:
GET,POST,PATCH,DELETE,PUT,HEAD,OPTIONS. - Each function receives a standard Web
Requestand returns a standard WebResponse. - The URL is derived from the folder path:
app/api/users/route.tsserves/api/users.
Because these are built on the platform's native Fetch API, the same mental model works on Node and Edge runtimes.
// app/api/users/route.ts
export async function GET(request: Request): Promise<Response> {
return Response.json({ users: ["Ada", "Linus"] });
}
export async function POST(request: Request): Promise<Response> {
const body = await request.json();
return Response.json({ created: body }, { status: 201 });
}Returning Responses
A handler must return a Response. Next.js gives you the native object plus a convenience helper.
Response.json(data, init)serializesdataand setsContent-Type: application/jsonautomatically.- Use the second
initargument to setstatusand customheaders. - For plain text or other payloads, construct
new Response(body, init)directly.
Picking the right status code is part of RESTful design: 200 for reads, 201 for creates, 204 for deletes with no body.
// Three idiomatic ways to respond
Response.json({ ok: true }); // 200 + JSON
Response.json({ id: 1 }, { status: 201 }); // 201 Created
new Response(null, { status: 204 }); // 204 No Content
new Response("pong", {
status: 200,
headers: { "Content-Type": "text/plain" },
});Reading the Request Body
The incoming Request is the same object you know from fetch on the client. Its body is a stream you consume once.
await request.json()parses a JSON payload.await request.text()reads raw text.await request.formData()reads multipart or URL-encoded form submissions.
You can only read the body once. If JSON parsing can fail (malformed input), wrap it in try/catch and return 400 Bad Request.
// app/api/posts/route.ts
export async function POST(request: Request) {
let body: { title?: string };
try {
body = await request.json();
} catch {
return Response.json({ error: "Invalid JSON" }, { status: 400 });
}
if (!body.title) {
return Response.json({ error: "title is required" }, { status: 422 });
}
return Response.json({ id: 1, title: body.title }, { status: 201 });
}Reading Query Parameters
For GET requests, filters and pagination usually arrive as query-string parameters. Parse them from the request URL.
new URL(request.url)gives you aURLobject.- Its
searchParamsis aURLSearchParamsinstance withget,getAll, andhas. - Convert numeric params explicitly — every value comes in as a string.
Next.js also exposes nextUrl via NextRequest, but the native URL approach keeps your handler runtime-agnostic.
// app/api/products/route.ts -> /api/products?page=2&q=phone
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const page = Number(searchParams.get("page") ?? "1");
const q = searchParams.get("q") ?? "";
return Response.json({ page, q });
}Dynamic Segments and Async Params
To handle a single resource by id, create a dynamic folder like app/api/users/[id]/route.ts. The segment is passed as the second argument.
Important Next.js 15 change: the params object is now a Promise. You must await it before reading values.
- Type the context as
{ params: Promise<{ id: string }> }. const { id } = await params;unwraps the segment.- Segment values are always strings, so parse numbers yourself.
// app/api/users/[id]/route.ts
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const user = { id, name: "Ada" };
return Response.json(user);
}A Full GET-by-id with 404
RESTful reads should return the resource on success and a proper 404 Not Found when it does not exist. Never return 200 with an empty body for a missing record.
- Look up the resource using the awaited
id. - If nothing is found, return
Response.json({ error }, { status: 404 }). - Otherwise return the resource with the default
200.
This handler is the canonical shape for /api/<resource>/[id].
// app/api/users/[id]/route.ts
const DB = new Map([["1", { id: "1", name: "Ada" }]]);
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const user = DB.get(id);
if (!user) {
return Response.json({ error: "User not found" }, { status: 404 });
}
return Response.json(user);
}PATCH for Partial Updates
PATCH updates part of a resource, while PUT replaces it entirely. For most CRUD APIs you want PATCH: the client sends only the fields that change.
- Read the dynamic
idfrom the awaited params. - Parse the JSON body for the changed fields.
- Merge the changes onto the existing record and return the updated resource with
200.
Return 404 if the target does not exist, and validate before merging.
// app/api/users/[id]/route.ts
export async function PATCH(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const existing = DB.get(id);
if (!existing) {
return Response.json({ error: "Not found" }, { status: 404 });
}
const changes = await request.json();
const updated = { ...existing, ...changes, id };
DB.set(id, updated);
return Response.json(updated);
}DELETE and 204 No Content
A successful DELETE typically returns 204 No Content with an empty body, signalling the resource is gone and there is nothing to send back.
- Confirm the resource exists; if not, return
404. - Remove it from your store.
- Return
new Response(null, { status: 204 })— do not callResponse.json, since a 204 must have no body.
Some teams prefer 200 with the deleted object; both are valid, but be consistent across your API.
// app/api/users/[id]/route.ts
export async function DELETE(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
if (!DB.has(id)) {
return Response.json({ error: "Not found" }, { status: 404 });
}
DB.delete(id);
return new Response(null, { status: 204 });
}Reading and Setting Headers
Headers carry auth tokens, content negotiation, and caching hints. The native Request.headers and Response init both use the standard Headers API.
request.headers.get("authorization")reads an incoming header (case-insensitive).- Set response headers via the
init.headersobject or aHeadersinstance. - Common ones:
Cache-Control,Location(for created resources), andWWW-Authenticate.
Returning 401 Unauthorized early keeps protected handlers clean.
// app/api/secret/route.ts
export async function GET(request: Request) {
const auth = request.headers.get("authorization");
if (auth !== "Bearer secret-token") {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
return Response.json(
{ data: "top secret" },
{ headers: { "Cache-Control": "no-store" } }
);
}Caching and the Runtime
In Next.js 15, GET Route Handlers are not cached by default (this changed from Next.js 14). You opt into static caching explicitly.
- Force caching with
export const dynamic = 'force-static'. - Set a revalidation window with
export const revalidate = 60(seconds). - Reading the request body, headers, or cookies makes a handler dynamic automatically.
Choose the runtime with export const runtime = 'edge' for low-latency global execution, or the default 'nodejs' when you need Node APIs.
// app/api/quote/route.ts
export const runtime = "edge";
export const revalidate = 60; // re-generate at most once per minute
export async function GET() {
return Response.json({ quote: "Stay curious", at: Date.now() });
}A Pure Request Router You Can Run
Route Handlers are thin wrappers over Web Request/Response. To prove the model is just standard JavaScript, here is a tiny self-contained router that dispatches by method and parses an id from the path — no framework required.
- It builds a real
Request, inspectsmethodandurl, and returns aResponse. - The same logic you would put inside
GET/POSTlives here. - This runs in any modern runtime with the Fetch API available.
async function handle(req: Request): Promise<Response> {
const { pathname } = new URL(req.url);
const id = pathname.split("/").pop();
if (req.method === "GET") {
return Response.json({ id, name: "Ada" });
}
if (req.method === "DELETE") {
return new Response(null, { status: 204 });
}
return Response.json({ error: "Method Not Allowed" }, { status: 405 });
}
async function main() {
const get = await handle(new Request("http://x/api/users/1"));
console.log(get.status, await get.json());
const del = await handle(
new Request("http://x/api/users/1", { method: "DELETE" })
);
console.log(del.status); // 204
}
main();Quick Check
You are writing app/api/users/[id]/route.ts in Next.js 15. How do you correctly read the id segment inside the GET handler?
Recap
You now know how to design RESTful Route Handlers on the native Web Request/Response API in Next.js 15.
- Export method-named async functions (
GET,POST,PATCH,DELETE) fromroute.ts. - Read input with
request.json(),request.formData(), andnew URL(request.url).searchParams. - Access dynamic segments via
const { id } = await params— params is a Promise in v15. - Respond with
Response.json(data, { status }); use201for creates,404for missing resources, and204(empty body) for deletes. - Remember
GETis uncached by default; opt in withdynamic/revalidate, and pickruntimeas needed.
These patterns give you clean, predictable, framework-agnostic API endpoints.
Belajar TypeScript dengan tutor AI — gratis
Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.
- Kursus
- 22
- Pelajaran
- 88
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Merancang Penangan Rute RESTful dengan API Permintaan Web” gratis?
Ya — teks lengkap “Merancang Penangan Rute RESTful dengan API Permintaan Web” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Next.js 15 Fullstack (App Router + Server Actions), upgrade ke CoddyKit PRO. Kursus Next.js 15 Fullstack (App Router + Server Actions) mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Merancang Penangan Rute RESTful dengan API Permintaan Web”?
Implementasikan penangan GET/POST/PATCH/DELETE menggunakan objek Request dan Response asli serta segmen dinamis. Kamu berlatih Next.js 15 Fullstack (App Router + Server Actions) dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Next.js 15 Fullstack (App Router + Server Actions)?
Tidak diperlukan pengalaman sebelumnya. Next.js 15 Fullstack (App Router + Server Actions) di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.
Berapa lama pelajaran “Merancang Penangan Rute RESTful dengan API Permintaan Web” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Next.js 15 Fullstack (App Router + Server Actions) ini?
Ya. Setiap pelajaran Next.js 15 Fullstack (App Router + Server Actions) menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Merancang Penangan Rute RESTful dengan API Permintaan Web
- Perbandingan Runtime Node dan Edge
- Respons Streaming dan ReadableStream dalam Penangan
- Validasi Permintaan dan Respons JSON Bertipe dengan Zod