963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
144 lines
3.4 KiB
Markdown
144 lines
3.4 KiB
Markdown
# Route Handlers
|
|
|
|
Create API endpoints with `route.ts` files.
|
|
|
|
## Basic Usage
|
|
|
|
```tsx
|
|
// app/api/users/route.ts
|
|
export async function GET() {
|
|
const users = await getUsers();
|
|
return Response.json(users);
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
const body = await request.json();
|
|
const user = await createUser(body);
|
|
return Response.json(user, { status: 201 });
|
|
}
|
|
```
|
|
|
|
## Supported Methods
|
|
|
|
`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`
|
|
|
|
## GET Handler Conflicts with page.tsx
|
|
|
|
**A `route.ts` and `page.tsx` cannot coexist in the same folder.**
|
|
|
|
```
|
|
app/
|
|
├── api/
|
|
│ └── users/
|
|
│ └── route.ts # /api/users
|
|
└── users/
|
|
├── page.tsx # /users (page)
|
|
└── route.ts # Warning: Conflicts with page.tsx!
|
|
```
|
|
|
|
If you need both a page and an API at the same path, use different paths:
|
|
|
|
```
|
|
app/
|
|
├── users/
|
|
│ └── page.tsx # /users (page)
|
|
└── api/
|
|
└── users/
|
|
└── route.ts # /api/users (API)
|
|
```
|
|
|
|
## Environment Behavior
|
|
|
|
Route handlers run in a **Server Component-like environment**:
|
|
|
|
- Yes: Can use `async/await`
|
|
- Yes: Can access `cookies()`, `headers()`
|
|
- Yes: Can use Node.js APIs
|
|
- No: Cannot use React hooks
|
|
- No: Cannot use React DOM APIs
|
|
- No: Cannot use browser APIs
|
|
|
|
```tsx
|
|
// Bad: This won't work - no React DOM in route handlers
|
|
import { renderToString } from 'react-dom/server';
|
|
|
|
export async function GET() {
|
|
const html = renderToString(<Component />); // Error!
|
|
return new Response(html);
|
|
}
|
|
```
|
|
|
|
## Dynamic Route Handlers
|
|
|
|
```tsx
|
|
// app/api/users/[id]/route.ts
|
|
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
const { id } = await params;
|
|
const user = await getUser(id);
|
|
|
|
if (!user) {
|
|
return Response.json({ error: 'Not found' }, { status: 404 });
|
|
}
|
|
|
|
return Response.json(user);
|
|
}
|
|
```
|
|
|
|
## Request Helpers
|
|
|
|
```tsx
|
|
export async function GET(request: Request) {
|
|
// URL and search params
|
|
const { searchParams } = new URL(request.url);
|
|
const query = searchParams.get('q');
|
|
|
|
// Headers
|
|
const authHeader = request.headers.get('authorization');
|
|
|
|
// Cookies (Next.js helper)
|
|
const cookieStore = await cookies();
|
|
const token = cookieStore.get('token');
|
|
|
|
return Response.json({ query, token });
|
|
}
|
|
```
|
|
|
|
## Response Helpers
|
|
|
|
```tsx
|
|
// JSON response
|
|
return Response.json({ data });
|
|
|
|
// With status
|
|
return Response.json({ error: 'Not found' }, { status: 404 });
|
|
|
|
// With headers
|
|
return Response.json(data, {
|
|
headers: {
|
|
'Cache-Control': 'max-age=3600',
|
|
},
|
|
});
|
|
|
|
// Redirect
|
|
return Response.redirect(new URL('/login', request.url));
|
|
|
|
// Stream
|
|
return new Response(stream, {
|
|
headers: { 'Content-Type': 'text/event-stream' },
|
|
});
|
|
```
|
|
|
|
## When to Use Route Handlers vs Server Actions
|
|
|
|
| Use Case | Route Handlers | Server Actions |
|
|
| ------------------------ | -------------- | -------------- |
|
|
| Form submissions | No | Yes |
|
|
| Data mutations from UI | No | Yes |
|
|
| Third-party webhooks | Yes | No |
|
|
| External API consumption | Yes | No |
|
|
| Public REST API | Yes | No |
|
|
| File uploads | Both work | Both work |
|
|
|
|
**Prefer Server Actions** for mutations triggered from your UI.
|
|
**Use Route Handlers** for external integrations and public APIs.
|