# HTTP methods used correctly

- **Pattern:** `ab-002169` (`saas-api-design.api-consistency.http-methods-correct`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002169
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002169)

## Why it matters

Using GET to delete resources or POST for all mutations violates HTTP semantics in ways that cause real damage: browsers and CDNs will cache or prefetch GET endpoints that actually mutate state, link prefetchers can trigger deletes without user intent, and CWE-749 (exposed dangerous methods) applies when destructive operations are reachable via safe-method verbs. Semantically incorrect methods also break API consumers who rely on HTTP conventions — retry logic in HTTP clients retries GET and PUT as safe/idempotent but not POST.

## Severity rationale

High because GET-based mutations can be triggered by prefetchers, cached by CDNs, or exploited via CSRF — any of which produces unintended data destruction or exposure.

## Remediation

Align each route handler export in `app/api/` with its actual semantic in one pass: GET reads only, POST creates, PATCH partially updates, PUT replaces, DELETE removes. In Next.js App Router this means changing the exported function name:

```ts
// Before (wrong)
export async function GET(req: Request) {
  await db.user.delete({ where: { id: req.nextUrl.searchParams.get('id') } })
}

// After (correct)
export async function DELETE(req: Request) {
  const { id } = await req.json()
  await db.user.delete({ where: { id } })
}
```

Update all client-side fetch calls to use the matching method. Work through your route list systematically — most AI-generated APIs default POST for everything and need a full sweep.

## Detection

- **ID:** `http-methods-correct`
- **Severity:** `high`
- **What to look for:** Enumerate all route handler files. For each, classify which HTTP method is exported and verify it uses the semantically correct HTTP method. Check for these anti-patterns: (1) GET requests that create, update, or delete data; (2) POST requests used for all mutations when PUT/PATCH/DELETE would be more appropriate; (3) DELETE operations implemented via POST or GET with a query parameter; (4) GET requests with a request body (not supported in all HTTP clients). Look for handler function names like `export async function GET`, `export async function POST`, etc. in Next.js App Router, or `req.method === 'POST'` branching in Pages Router handlers.
- **Pass criteria:** GET handlers read data only, POST creates resources, PUT/PATCH updates resources, DELETE deletes resources. Some overlap is acceptable (e.g., POST used for complex search queries, RPC-style actions via POST).
- **Fail criteria:** Any of these are present: GET handlers that mutate data; POST handlers doing all mutations with no PUT/PATCH/DELETE; DELETE operations triggered via GET (e.g., `/api/delete-user?id=123`).
- **Skip (N/A) when:** Fewer than 2 API routes exist. Signal: only 0 or 1 route handler files detected.
- **Detail on fail:** Identify the specific violation (e.g., "GET /api/delete-account mutates data; all updates use POST rather than PUT/PATCH"). Max 500 chars.
- **Remediation:** Align HTTP methods with their standard semantics in `app/api/` route files. Use GET for safe, idempotent reads. Use POST for resource creation or non-idempotent actions. Use PUT to replace a resource entirely (full update), PATCH for partial updates, and DELETE for removal. Update both the route handler export names and any client-side fetch calls. Most AI-generated APIs default to POST for everything — work through your route list and reassign appropriately.

## External references

- iso-25010 maintainability.modifiability
- cwe CWE-749

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-002169
