Phase 2

REST and OpenAPI

Learn to make APIs that are predictable, clear to use, and safe to call more than once.

#REST#OpenAPI#idempotency

What "RESTful" is actually supposed to mean

REST (Representational State Transfer) is a set of architectural constraints, not a technology. The two that matter most day to day:

Resource-oriented URLs. A URL identifies a thing (a resource), not an action. /users/42 is a resource. /getUser?id=42 or /api/deleteUserById describes an action baked into the URL - that's RPC dressed up as REST, and it's extremely common in real codebases despite not being what REST actually prescribes.

Interactive example

Resource-oriented vs RPC in name only

Two APIs doing the same work, one following REST's constraints and one not. Toggle between them.

Resource-oriented

The URL names a thing; the verb says what to do with it.

  • GET /users/42 reads it, DELETE /users/42 removes it - same URL, different verb.
  • The meaning lives in the method, so the path stays a noun.
  • The status code reports the outcome: 200, 201, 404, 409.
  • Caches and retry logic can rely on GET and PUT behaving as documented.

StatelessnessStatelessnessA design where no individual server process is the only place that remembers something about a client. State gets pushed to the client (a token) or shared storage (Redis, a database), so any server can handle any request.. Every request carries everything the server needs to process it - the server holds no memory of a client's prior requests between calls. This is the same idea covered in the statelessness topic: it's what lets any server instance handle any request, which is what makes horizontal scalingHorizontal scalingHandling more load by adding more machines running the same code, instead of making one machine bigger (vertical scaling). Usually the more sustainable path at real scale, but it only works if no server is the only place holding unique state. straightforward.

A third constraint, uniform interface via HTTP verbs, means the verb carries the meaning, and the URL just names the resource:

VerbMeaningIdempotent?
GETRead a resourceYes
POSTCreate a new resource, or trigger a non-idempotent actionNo
PUTReplace a resource entirelyYes
PATCHPartially update a resourceNot guaranteed
DELETERemove a resourceYes

PUT vs PATCH vs POST, where people actually get it wrong

PUT /users/42 with a body of { "name": "Alex" } should mean "the entire user resource is now exactly this" - if the user previously had an email field and it's missing from the body, a strict PUT implementation removes it, because PUT means full replacement. Sending the same PUT request twice produces the same end state both times - that's what makes it idempotent.

PATCH /users/42 with { "name": "Alex" } means "update only the name field, leave everything else alone." This is the verb most APIsAPIA defined way for one piece of code to ask another to do something, without needing to know how it happens internally. Not a specific technology - a function signature, a library's exports, and a REST endpoint are all APIs. actually want when they say "update," but a huge number of real-world APIs use PUT for partial updates out of habit, which technically breaks the full-replacement contract PUT is supposed to guarantee.

POST /users (note: no ID in the URL) creates a new resource and is not idempotent by default - calling it twice with the same body creates two separate users. This is the specific behavior the idempotencyIdempotencyThe property of an operation where doing it multiple times has the same effect as doing it once - like pressing an elevator button repeatedly. Critical for safely retrying requests over an unreliable network. topic covers in more depth, including how an Idempotency-Key header lets clients safely retry a POST without risking duplicate creation.

What OpenAPI is actually for

An OpenAPI spec (formerly "Swagger") is a machine-readable YAML or JSON document describing every endpoint, request shape, response shape, and status code an API returns. Treating it as "just documentation" undersells what it enables:

A minimal path definition looks like:

yaml
paths:
  /users/{id}:
    get:
      summary: Get a user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: User found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "404":
          description: User not found

Nothing about that YAML is documentation-only - it's a machine-checkable contract that codegen tools, validators, and mock servers can all consume the same way.

REST-in-name-only, the common failure mode

An API that uses only POST for everything, tunnels every operation through query parameters or a single catch-all endpoint, and returns 200 OK for both successes and errors with an { "error": true } field buried in the body is not RESTful, even if the team calls it a REST API. It works, plenty of production systems look exactly like this, but it forfeits the predictability - resource-shaped URLs, correct status codes, verb semantics - that makes REST useful as a shared convention across teams and tools in the first place.

Interview prep

This topic comes up in interviews - 3 questions, leveled by role.

See the questions →