REST APIs: Resource-Oriented Interfaces Using HTTP Semantics
📑 On this page
- A concrete example: orders
- Resources are concepts
- URLs identify resources
- Representations
- GET reads without intended mutation
- POST creates or submits work
- PUT replaces a known resource
- PATCH applies a partial change
- DELETE requests removal
- Stateless requests
- HTTP status semantics
- Caching
- Conditional requests
- Collections and filtering
- Relationships and links
- Actions that do not fit CRUD
- Asynchronous operations
- Compatibility
- Knowledge check
- The one idea to remember
REST is frequently used to mean "an API that sends JSON over HTTP." The architectural idea is more specific.
A REST-like API models information as resources addressed by URLs and uses standard HTTP methods, representations, status semantics, and caching rules.
Not every practical HTTP API follows every formal REST constraint. The useful goal is a predictable interface that works with HTTP rather than hiding all behavior behind one generic call.
A concrete example: orders
GET /orders/42requests a representation of order 42.
DELETE /orders/42requests deletion according to the server's authorization and business rules.
The URL identifies the resource. The method communicates the operation.
This is clearer than:
POST /api
{ "action": "deleteOrder", "id": 42 }Resources are concepts
A resource can be:
- Customer
- Order
- Product
- Invoice
- Search result collection
- Current session
- Report generation job
A resource is not necessarily one database row or file.
/account-summary/1042 may combine several data sources.
Model resources around domain concepts clients understand, not storage implementation.
URLs identify resources
Common URL shapes include:
/orders
/orders/42
/customers/1042/ordersUse nouns for resources and let methods express general operations.
URLs should be stable and understandable.
Avoid deeply nested paths that require callers to know every internal ownership relationship.
A globally unique order may be reachable as /orders/42 even if it also appears in a customer's order collection.
Representations
A resource can have representations in JSON, XML, HTML, or another format.
Example JSON:
{
"id": "42",
"status": "paid",
"total": {
"amount": "75.00",
"currency": "USD"
}
}The representation is not the resource itself.
The server may calculate fields, hide sensitive values, or include links.
Content negotiation can use headers such as Accept and Content-Type, though many APIs standardize on one format for simplicity.
GET reads without intended mutation
GET retrieves a representation.
It is safe in HTTP semantics: the caller does not request a state change.
Servers may still log, count, or cache the request as incidental effects, but a crawler or retry should not create an order.
GET responses can often be cached.
Do not place secrets or large sensitive payloads in URLs because paths and query strings may appear in logs, browser history, and intermediary systems.
POST creates or submits work
POST /orders may create an order:
POST /orders
Content-Type: application/json
{
"cartId": "c-17",
"shippingAddressId": "a-9"
}A successful response might use:
201 Created
Location: /orders/42POST is not inherently idempotent. Repeating it may create another resource.
Use idempotency keys when network retry could duplicate consequential work.
PUT replaces a known resource
PUT commonly means create or replace the representation at a known URL:
PUT /users/1042/preferencesSending the same complete representation repeatedly should produce the same intended state.
That makes PUT idempotent in HTTP semantics.
Be clear whether omitted fields are removed, reset, or preserved. If the operation is partial rather than replacement, PATCH is often more expressive.
PATCH applies a partial change
PATCH updates part of a resource.
PATCH /orders/42
{
"deliveryNote": "Leave with reception"
}The API must define:
- Patch document format
- Null versus omission
- Allowed fields
- Conflict behavior
- Validation
A patch can be idempotent, but is not automatically so.
For example, "increment quantity by one" changes again on every retry.
DELETE requests removal
DELETE /orders/42 requests deletion or domain-specific removal.
The server may:
- Delete permanently
- Mark inactive
- Reject because records must be retained
- Start an asynchronous deletion workflow
HTTP method semantics do not override business and legal constraints.
Document what deletion means and what subsequent GET requests return.
Repeated DELETE requests should normally converge on the resource being absent.
Stateless requests
REST includes a stateless constraint: each request contains the information necessary to understand it, rather than depending on hidden server conversation state.
Authentication can use a session identifier, but the request carries that identifier.
Statelessness supports:
- Horizontal scaling
- Intermediaries
- Independent request handling
The application still has state in databases and resources.
Stateless requests do not mean a stateless business system.
HTTP status semantics
Useful codes include:
200 OK201 Created204 No Content400 Bad Request401 Unauthorized403 Forbidden404 Not Found409 Conflict422 Unprocessable Content429 Too Many Requests500 Internal Server Error503 Service Unavailable
Choose codes consistently and add structured error details.
Do not return 200 with { "success": false } for every failure. That discards protocol semantics used by clients, caches, gateways, and monitoring.
Caching
HTTP supports caching through headers such as:
Cache-ControlETagLast-ModifiedVary
A product catalog response may be reusable briefly.
A private account response should prevent shared caching or vary safely by authorization.
Correct caching can reduce latency and load.
Incorrect caching can leak personalized data, so cache behavior belongs in API design.
Conditional requests
An ETag identifies a representation version.
For efficient reads:
If-None-Match: "order-42-v7"The server can return 304 Not Modified.
For safe updates:
If-Match: "order-42-v7"The server changes the resource only if the version still matches, preventing one client from silently overwriting another's update.
Conditional requests connect HTTP semantics to concurrency control.
Collections and filtering
GET /orders?status=unpaid&customerId=1042can represent a filtered collection.
Define:
- Supported filters
- Sort order
- Pagination
- Maximum page size
- Consistency
Avoid accepting arbitrary field or query expressions that expose internal schema and create unbounded database work.
Collection design must protect both usability and resource cost.
Relationships and links
Representations can include links:
{
"id": "42",
"customer": "/customers/1042",
"items": "/orders/42/items"
}Links help clients discover related resources and reduce URL construction assumptions.
Formal REST emphasizes hypermedia as the engine of application state, though many real APIs use documented URL templates instead.
Even without full hypermedia, returning canonical resource URLs improves clarity.
Actions that do not fit CRUD
Business operations such as:
- Cancel order
- Capture payment
- Approve refund
- Rotate key
may not fit simple field updates.
Model an action as a resource or explicit subresource:
POST /orders/42/cancellationsThis creates an auditable cancellation request.
Do not force every domain action into PATCH status when the transition has validation, identity, and side effects.
Asynchronous operations
Long work can return:
202 Accepted
Location: /report-jobs/r-77The client polls the job resource or receives a webhook.
The job representation can expose:
- Pending
- Running
- Succeeded
- Failed
- Output link
This is clearer than keeping one HTTP connection open indefinitely or pretending acceptance means completion.
Compatibility
Safer changes include:
- Adding optional fields
- Adding new resources
- Adding new enum values when clients tolerate them
Breaking changes include:
- Removing fields
- Redefining meaning
- Changing type
- Tightening validation unexpectedly
- Changing default ordering
Clients should ignore unknown response fields where appropriate.
Servers should version or migrate incompatible changes deliberately.
Knowledge check
- How is a resource different from a database row?
- Why should GET not create a business side effect?
- How do PUT and PATCH usually differ?
- What can
If-Matchprevent? - Why might a cancellation be modeled as its own resource?
The one idea to remember
REST-like APIs use resource URLs and HTTP's existing methods, status, caching, and conditional semantics to create predictable contracts. Good design follows domain meaning rather than reducing every operation to generic CRUD.