REST API Design: What Every Self-Taught Developer Gets Wrong

Self-taught developers build APIs that work but don't follow conventions that teams expect. Here's the REST API design knowledge that makes your APIs professional.

The Gap Between 'Works' and 'Professional'

A self-taught developer's first API typically works. It accepts requests, processes data, and returns responses. But it often: uses inconsistent naming conventions, returns different error formats from different endpoints, mixes concerns (authentication logic inside business logic), doesn't version the API, and uses HTTP methods and status codes incorrectly. None of these problems prevent the API from working. All of them create friction for other developers (including your future self) who need to use or maintain it.

HTTP Methods: What They Actually Mean

Most vibe-coded APIs use GET and POST for everything. REST has specific semantics for each method that every API consumer expects. GET: retrieve data, should be idempotent (calling it 100 times has same effect as calling once), never modifies state. POST: create a resource or trigger an action, not idempotent. PUT: replace a resource completely. PATCH: partially update a resource (only the fields you send). DELETE: remove a resource. The mistake: using POST for everything or GET for operations that modify state (never do this — browsers preload GET URLs).

// Anti-pattern: POST for everything
POST /api/users/get-all
POST /api/users/delete-user
POST /api/users/update-email

// REST convention:
GET    /api/users              // list all users
GET    /api/users/:id          // get one user
POST   /api/users              // create a user
PUT    /api/users/:id          // replace a user (all fields)
PATCH  /api/users/:id          // update specific fields
DELETE /api/users/:id          // delete a user

// Nested resources:
GET    /api/users/:id/posts    // get all posts by a user
POST   /api/users/:id/posts    // create a post for a user

Status Codes: Use Them Semantically

Returning 200 OK for everything — including errors — breaks every API client that checks status codes, which is all of them. The codes you need to know and use correctly: 200 (OK), 201 (Created — for successful POST), 204 (No Content — for successful DELETE), 400 (Bad Request — invalid input), 401 (Unauthorized — not authenticated), 403 (Forbidden — authenticated but no permission), 404 (Not Found), 409 (Conflict — duplicate resource), 422 (Unprocessable Entity — validation error), 429 (Too Many Requests), 500 (Internal Server Error).

// What most self-taught APIs return:
app.post('/api/users', async (req, res) => {
  if (!req.body.email) {
    return res.json({ error: 'Email required' }) // Status 200! This is wrong.
  }
  // ...
  res.json({ success: true, user })
})

// REST-correct version:
app.post('/api/users', async (req, res) => {
  if (!req.body.email) {
    return res.status(400).json({ 
      error: 'validation_error',
      message: 'Email is required',
      field: 'email'
    })
  }
  // ...
  res.status(201).json({ user }) // 201 = Created
})

Consistent Error Responses

One thing that signals a professional API: every error response has the same shape. Not 'sometimes an object with error, sometimes a string, sometimes nothing.' A consistent error format lets clients write one error handling function instead of five. Pick a format and stick to it across every endpoint. The widely-adopted format follows RFC 7807 (Problem Details for HTTP APIs): type, title, status, detail, and optionally instance (the specific URL that generated the error).

Authentication, Versioning, and Documentation

Three things that separate APIs developers want to use from APIs they have to use. Authentication: JWT in Authorization header, never in query params (they appear in server logs). Versioning: /api/v1/ prefix so you can make breaking changes without destroying existing clients. Documentation: even a Postman collection with example requests is better than nothing. If you use TypeScript with Zod for validation, tools like tRPC and OpenAPI generators can produce documentation automatically. The API Design module at Beyond Vibe Code builds a properly designed REST API with authentication, versioning, and documentation as the capstone project.