InTab

Blog

What is a REST API? Resources, verbs and the rules that matter

By Uxair Ijaz · 2026-11-06 · 11 min read

Every developer meets REST on day one, yet most API mistakes — verbs in URLs, status codes as an afterthought, sessions pasted into requests — come from never being taught what REST actually says. This guide explains it from first principles, with a full worked example, and ends with the parts of the doctrine professionals keep and the parts they quietly drop.

The one-sentence definition

REST (Representational State Transfer) is a style of API where URLs name resources, HTTP methods act on them, and every request carries everything the server needs. That last part — no server-side session — is what "stateless" means, and it is the constraint everything else follows from.

It comes from Roy Fielding's 2000 dissertation, which described how the web itself works: browsers fetch representations (HTML, JSON) of resources (a page, a photo) using a uniform interface (GET, POST). REST applies the same architecture to APIs.

Resources: URLs are nouns

A resource is a thing your API talks about. The URL identifies it; the method says what to do; the body carries the details.

GET    /orders              → the collection of orders
GET    /orders/42           → one order
POST   /orders              → create an order
PUT    /orders/42           → replace order 42
PATCH  /orders/42           → partially update order 42
DELETE /orders/42           → delete order 42
GET    /orders/42/items     → order 42's line items

The conventions professionals keep:

  • Plural nouns (/orders, never /order or /getOrder). GET /orders/42 reads as "order 42 from the orders collection".
  • No verbs in URLs. The method is the verb. POST /orders/42/cancel is the accepted exception for actions that are genuinely not CRUD — or model it as a resource: POST /orders/42/cancellation.
  • Nest for ownership, two levels maximum. /customers/7/orders says "orders belonging to customer 7". Beyond that, flatten: /orders/42/items, not /customers/7/orders/42/items/9/days.
  • IDs are opaque. Users never parse them; if a client needs a date range it uses query parameters, not ID arithmetic.

The methods, and what they promise

Each method carries a contract that clients and caches rely on:

Method Meaning Safe (no side effects) Idempotent (same result if repeated)
GET read yes yes
PUT replace no yes
PATCH partially update no not guaranteed
POST create / process no no
DELETE remove no yes

Idempotency is the property network code is built on: a client that times out on PUT can simply retry. A retried POST may create two orders — which is why payment APIs issue idempotency keys (see our guide to designing API responses).

PATCH deserves one note: a body of {"name": "X"} means "change the name", but the JSON Patch standard means "apply this operation". Both exist in the wild; document which one your API speaks.

Statelessness: the request carries everything

The server keeps no session between requests. Every call presents its own credentials, and every call is understandable alone:

curl https://api.example.com/orders/42 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Accept: application/json"

That token is usually a JWT (what a JWT is, or try one in our JWT decoder). Statelessness is why REST scales horizontally: any server behind the load balancer can answer any request, because none of them is holding a conversation.

The professional exception: nobody stores credentials in URLs, and nobody passes "user_id" as a parameter and trusts it. Identity comes from the token; a user_id parameter is a filter, never who you are.

A complete worked example

Creating an order, start to finish:

Request

POST /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json
Idempotency-Key: 8f3e-unique-per-attempt

{ "items": [ { "sku": "tee-blue-m", "qty": 2 } ], "ship_to": "addr_91" }

Response — success

HTTP/1.1 201 Created
Location: /orders/42
Content-Type: application/json

{ "id": "42", "status": "placed", "total": 54.00, "currency": "USD",
  "items": [ { "sku": "tee-blue-m", "qty": 2 } ] }

Response — validation failure

HTTP/1.1 422 Unprocessable Content
Content-Type: application/json

{ "error": "validation_failed",
  "message": "2 fields are invalid.",
  "fields": { "items.sku": "Unknown SKU tee-blue-L" } }

Read the exchange like a professional: the status code alone tells monitoring whether anything went wrong; Location tells the client where the new resource lives; the 422 body says exactly which field failed and why; the client can retry the whole thing safely because of the idempotency key. Status codes are a language of their own — we cover every code worth using in its own guide.

Cross-cutting conventions

Filtering and paging use query parameters: GET /orders?status=placed&limit=20&cursor=eyJpZCI6NDF9. Page numbers break when rows are inserted; cursors do not — the trade-offs are in the response design guide.

Versioning belongs in the path (/v1/orders) for almost every team: visible in logs, trivially routable, and honest about the fact that API versions are deployments, not headers. GitHub's /v3/, /v4/ split is the pattern people recognise.

Errors are structured, never a 200 with {"error": "..."} inside — that breaks every monitoring tool, cache and retry library ever written.

Documentation is OpenAPI. A machine-readable spec (openapi.yaml) generates docs, SDKs and mocks; professionals treat it as the contract, not an afterthought. If a handler drifts from the spec, the spec wins.

What REST is not

  • Not a protocol. REST has no envelope, no mandated headers, no registry — which is its strength and why two "REST" APIs can feel so different.
  • Not RPC with JSON. POST /getOrders, POST /createUser and POST /deleteOrder?id=42 are remote procedure calls wearing REST URLs. They work, but they forfeit caching, idempotency and every tool built on the uniform interface.
  • Not necessarily HATEOAS. The textbook demands that clients navigate purely by hyperlinks in responses. Almost no public API does this fully; Stripe, GitHub and Stripe-likes ship a url field per object, which is the pragmatic 80%.

What professionals choose in 2026

  • REST as the default for public and third-party APIs: cacheable, debuggable with curl, universally understood.
  • JSON, not XML; camelCase or snake_case fields, picked once (naming conventions).
  • OpenAPI-documented, versioned in the path, bearer-token authenticated.
  • gRPC for internal service-to-service traffic where performance and typed contracts beat debuggability.
  • Hypermedia only where clients are unknown and long-lived — the rarest case.

If SOAP is on your desk instead, that is a different conversation with different history: see SOAP APIs in depth.

Checklist: your first REST endpoint, done right

  1. Plural resource noun, kebab-case path (/invoice-templates), no verbs.
  2. Correct method for the intent; GET never changes anything.
  3. Correct status code: 201 + Location on create, 422 with field details on bad input.
  4. Bearer token for identity; request carries everything (stateless).
  5. Idempotency key accepted on POST.
  6. Errors structured, documented in OpenAPI, consistent across the API.
  7. Pagination and filtering via query parameters from day one.

Get those seven right and your API will feel familiar to everyone who has ever used Stripe, GitHub or Shopify — which is the entire point of REST.

Tools in this article

  • JSON Formatter: Beautify, minify, validate and sort JSON. Handles escaped/stringified JSON.
  • JWT Encoder / Decoder: Decode, verify and sign JSON Web Tokens: HS, RS, PS, ES and EdDSA, with key generation.
  • URL Encoder: Percent-encode and decode URLs; parse URL parts and query parameters.