Back to blog
#api #backend #rest #best-practices

6 Common API Mistakes (And How to Fix Them)

Adam Abdel-Djamal 6 min read

From wrong HTTP methods to leaking sensitive data β€” the errors most developers make when building their first API, and the concrete fixes.

Building an API feels straightforward until your first production incident. Most bugs aren't complex β€” they're the same six mistakes repeated across thousands of codebases. Here's what they are and how to stop making them.


1. Using the Wrong HTTP Method

The most visible mistake. Using GET to delete a resource, or POST for everything because "it works."

# ❌ Deleting with GET β€” catastrophic if a browser prefetches this URL
GET /api/users/42/delete

# βœ… Correct
DELETE /api/users/42

HTTP methods carry semantic meaning that clients, proxies, and caches rely on. GET must be idempotent and safe (no side effects). POST creates. PUT/PATCH update. DELETE removes. Violating these conventions breaks caching, browser history, and every HTTP client that follows the spec.


2. Wrong Status Codes

Returning 200 OK for an error response is the most common mistake in junior APIs.

// ❌ Status 200, but it's an error
{
  "success": false,
  "error": "User not found"
}

// βœ… Status 404 β€” the client knows immediately without parsing the body
{
  "error": "User not found",
  "code": "USER_NOT_FOUND"
}

The codes that matter most:

CodeWhen to use it
200Success with a body
201Resource created (POST)
204Success, no body (DELETE)
400Invalid input from the client
401Not authenticated
403Authenticated but not authorized
404Resource doesn't exist
422Input syntactically valid but semantically wrong
429Rate limit exceeded
500Server error (never the client's fault)

3. Trusting Client Input

Every value sent by a client is a potential attack vector.

// ❌ Never do this
$id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $id";
// SQL injection: ?id=1 OR 1=1

// βœ… Always validate and sanitize
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT);
if (!$id) {
    return response()->json(['error' => 'Invalid ID'], 400);
}
$user = User::findOrFail($id); // parameterized query

Validate: type, format, length, range. Sanitize before any database or filesystem operation. Never trust what arrives in the request body, headers, or query string.


4. Leaking Sensitive Data

Returning the full database object without filtering is an invitation to a data breach.

// ❌ Returning the raw User model
{
  "id": 42,
  "email": "user@example.com",
  "password": "$2b$12$...",
  "stripe_customer_id": "cus_xxx",
  "internal_notes": "flagged for review",
  "created_at": "2024-01-01"
}

// βœ… Return only what the client actually needs
{
  "id": 42,
  "email": "user@example.com",
  "created_at": "2024-01-01"
}

Use serializers, DTOs, or API Resources (Laravel) to explicitly define what gets exposed. The rule: opt-in, not opt-out. Start with nothing, add what's needed.


5. Inconsistent Error Format

When every endpoint returns errors differently, every client has to handle every format.

// ❌ Endpoint A
{ "message": "Not found" }

// ❌ Endpoint B
{ "error": true, "msg": "Validation failed", "fields": ["email"] }

// ❌ Endpoint C
"Internal server error"

// βœ… One format, everywhere
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "The request contains invalid fields.",
    "details": [
      { "field": "email", "issue": "Invalid email format" }
    ]
  }
}

Define your error envelope once. Apply it everywhere via a global exception handler. Clients β€” including your own frontend β€” will thank you.


6. No API Versioning

Changing an endpoint response breaks every client using it. Without versioning, you can never evolve the API.

# ❌ No version β€” any breaking change affects all clients immediately
GET /api/users

# βœ… Versioned β€” v1 stays stable, v2 introduces breaking changes safely
GET /api/v1/users
GET /api/v2/users

Version from day one, even if you only have v1. The cost of adding /v1/ later β€” after clients are in production β€” is much higher than the cost of including it from the start.


The Takeaway

None of these mistakes require advanced knowledge to fix. They require discipline: a checklist before every endpoint ships.

  • HTTP method matches the operation's semantics
  • Status code is accurate
  • All input is validated before use
  • Response only exposes necessary fields
  • Errors follow the global format
  • URL includes an API version

Share this article

AA

Adam Abdel-Djamal

Full Stack Developer

Adam Abdel-Djamal is a Full-Stack & AI Engineer crafting high-performance web applications with Nuxt, Vue, Laravel, and autonomous AI agents.

Related Articles

Adam Abdel-Djamal

Full Stack Web Developer

We use cookies to remember your language preference and measure anonymous traffic. Privacy Policy