0% found this document useful (0 votes)
17 views10 pages

Rest API Design

This document outlines the principles, patterns, and best practices for designing REST APIs, including the definition of REST, HTTP methods, URL design, status codes, and request/response design. It emphasizes the importance of consistent documentation, security measures, and versioning strategies to ensure a robust API. Additionally, it compares REST with GraphQL and highlights the significance of thoughtful design in creating intuitive and durable APIs.

Uploaded by

Pedro Henrique
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views10 pages

Rest API Design

This document outlines the principles, patterns, and best practices for designing REST APIs, including the definition of REST, HTTP methods, URL design, status codes, and request/response design. It emphasizes the importance of consistent documentation, security measures, and versioning strategies to ensure a robust API. Additionally, it compares REST with GraphQL and highlights the significance of thoughtful design in creating intuitive and durable APIs.

Uploaded by

Pedro Henrique
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

REST API Design

Principles, Patterns, and Best Practices

Programming Guides

1. What is REST?

REST (Representational State Transfer) is an architectural style for distributed hypermedia systems, defined by Roy
Fielding in his 2000 doctoral dissertation. It is not a protocol or a standard but a set of constraints that, when applied,
produce a uniform interface between clients and servers.

A RESTful API uses HTTP as the transport layer and treats everything - users, orders, articles, sessions - as a resource
identified by a URL. Clients interact with these resources using the standard HTTP methods (GET, POST, PUT,
PATCH, DELETE).

REST has become the dominant style for public APIs because it is simple, uses widely understood standards, and
works naturally with browsers and HTTP tooling.

The Six REST Constraints


* Client-Server: Separation of concerns. The client handles UI; the server handles data.
* Sta
bet

2. HTTP Methods

Each HTTP method carries semantic meaning. Using the correct method makes your API self-documenting and
interoperable with HTTP infrastructure like caches and proxies.

Page 1
GET
Retrieve a resource or list of resources. Safe (no side effects) and idempotent (same result every time). Never use GET
to modify state.

POST
Create a new resource. Not idempotent: calling POST twice creates two resources. Returns 201 Created with a Location
header pointing to the new resource.

PUT
Replace a resource entirely. Idempotent: calling PUT twice has the same result as calling it once. Requires the full
resource representation in the request body.

PATCH
Partially update a resource. Only the fields included in the body are modified. Should be idempotent in practice, though
not strictly required.

DELETE
Remove a resource. Idempotent: deleting an already-deleted resource returns 404 but does not cause an error state.

HEAD
Same as GET but returns only headers, no body. Useful for checking if a resource exists or getting metadata without
downloading the full payload.

OPTIONS
Returns the HTTP methods supported for a given URL. Used in CORS preflight requests and API discovery.

3. URL Design

Good URL design makes an API intuitive and predictable. URLs should identify resources, not actions. The HTTP
method carries the action; the URL carries the identity.

Core Rules
* Use nouns, not verbs: /users not /getUsers or /createUser
* Us

Resource Examples
# Users resource
GET /users -> list all users
POST /users -> create a user
GET /users/{id} -> get one user

Page 2
PUT /users/{id} -> replace user
PATCH /users/{id} -> update user fields
DELETE /users/{id} -> delete user

# Nested resource: posts owned by a user


GET /users/{id}/posts -> list this user's posts
POST /users/{id}/posts -> create a post for this user

# Filtering and pagination via query params


GET /articles?tag=python&page=2&limit=20
GET /orders?status=pending&sort=created_at&order=desc

4. HTTP Status Codes

Status codes are part of the HTTP contract. Using them correctly allows clients to handle responses programmatically
without parsing error messages.

Code Name When to use

200 OK Successful GET, PUT, PATCH


201 Created Successful POST - resource created
202 Accepted Request accepted, processed asynchronously
204 No Content Successful DELETE or PUT with no body
301 Moved Permanently URL has changed permanently
304 Not Modified Cached response is still valid (ETag match)
400 Bad Request Malformed request, invalid JSON
401 Unauthorized Missing or invalid authentication
403 Forbidden Authenticated but not authorized
404 Not Found Resource does not exist
405 Method Not Allowed HTTP method not supported for this URL
409 Conflict State conflict (e.g., duplicate email)
422 Unprocessable Entity Validation failed on a well-formed request
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Unexpected server failure
503 Service Unavailable Server overloaded or down for maintenance

5. Request and Response Design

Consistent request and response shapes reduce cognitive overhead for API consumers. Establish conventions early
and apply them uniformly.

Response Envelope
Wrap responses in a consistent envelope so clients can handle all responses uniformly:

// Success response
{
"data": {
"id": 42,

Page 3
"name": "Alice",
"email": "alice@[Link]",
"created_at": "2026-03-17T[Link]Z"
},
"meta": {
"request_id": "req-abc-123"
}
}

// Error response
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Email is already in use",
"details": [
{ "field": "email", "issue": "must be unique" }
]
}
}

Pagination
Always paginate collections. Never return unbounded lists. Two common strategies:

Offset pagination: Simple but has issues at scale (items shift if data changes).
Cursor pagination: Stable across mutations; better for real-time or large datasets.

// Offset pagination response


{
"data": [ ... ],
"pagination": {
"total": 1450,
"page": 3,
"per_page": 20,
"total_pages": 73
}
}

// Cursor pagination response


{
"data": [ ... ],
"pagination": {
"next_cursor": "eyJpZCI6IDEwMH0=",
"has_more": true
}
}

6. Authentication and Authorization

Authentication answers 'who are you?' Authorization answers 'what are you allowed to do?' Every API needs both. The
most common approaches:

Page 4
API Keys
Simple static tokens sent in headers. Good for server-to-server calls. Revoke by rotating the key. No user context - not
suitable for user-facing flows.

Authorization: ApiKey sk_live_abc123xyz

Bearer Tokens (JWT)


JSON Web Tokens (JWT) are signed tokens that carry claims (user ID, roles, expiry). The server validates the signature
without a database lookup. Stateless and scalable. Use short expiry (15m) with refresh tokens for security.

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Decoded JWT payload:


{
"sub": "user_42",
"roles": ["admin"],
"exp": 1742212800,
"iat": 1742209200
}

OAuth 2.0
OAuth 2.0 is the industry standard for delegated authorization. It allows a user to grant a third-party application limited
access to their account without sharing their password. The most common flow for web apps is the Authorization Code
flow with PKCE.

7. Versioning

APIs evolve. Versioning lets you make breaking changes without breaking existing clients. There are three common
strategies:

* URL versioning (most common): /v1/users, /v2/users. Explicit and easy to route.
* He

Best practice: maintain at least one previous major version for 6-12 months after releasing a new one. Communicate
deprecation timelines clearly via headers and documentation.

Deprecation-Header: true
Sunset: Sat, 01 Jan 2027 [Link] GMT

8. Rate Limiting and Throttling

Rate limiting protects your API from abuse and ensures fair usage. Always communicate limits to clients via response
headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 342
X-RateLimit-Reset: 1742213000

Page 5
Retry-After: 60

When a client exceeds the limit, return 429 Too Many Requests with a Retry-After header indicating how many seconds
to wait before retrying.

Common strategies include fixed window (simple), sliding window (fairer), and token bucket (allows short bursts). Use a
distributed cache like Redis to enforce limits across multiple API server instances.

9. Idempotency Keys

Idempotency is critical for non-idempotent operations like POST (payments, order creation). If a network failure occurs
after the server processes a request but before the client receives the response, the client does not know if the
operation succeeded.

Solution: clients send a unique Idempotency-Key header. The server stores the result and returns the same response on
retries with the same key, without processing the operation twice.

POST /payments
Idempotency-Key: a4b3c2d1-e5f6-7890-abcd-ef1234567890
Content-Type: application/json

{ "amount": 5000, "currency": "USD", "to": "user_99" }

# Retry with the same key -> same response, no double charge

10. Documentation and Contracts

An API is only as good as its documentation. Without clear docs, consumers will misuse endpoints, make incorrect
assumptions, and flood your support channels.

OpenAPI (formerly Swagger) is the de facto standard for describing REST APIs. An OpenAPI specification is a YAML or
JSON file that describes every endpoint, request/response schema, authentication method, and status code. From this
spec you can auto-generate client SDKs, server stubs, and interactive documentation.

Best practices for documentation:

* Document every endpoint: method, URL, parameters, request body, all possible responses.
* Pro

OpenAPI Example Snippet


openapi: 3.0.3
info:
title: User API

Page 6
version: '1.0'
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

11. Caching Strategies

HTTP provides a rich set of caching primitives that can dramatically reduce latency and server load when used correctly.
Caching is most valuable for GET responses that are expensive to compute and change infrequently.

Cache-Control Header
Cache-Control directives tell clients and intermediaries how to cache a response:

# Public cache, valid for 5 minutes


Cache-Control: public, max-age=300

# Private (browser only), 1 hour


Cache-Control: private, max-age=3600

# Never cache (sensitive data)


Cache-Control: no-store

# Can cache but must revalidate


Cache-Control: no-cache

ETags and Conditional Requests


An ETag is a hash of the response content. The client stores it and sends it on subsequent requests via If-None-Match.
If the content has not changed, the server returns 304 Not Modified with no body, saving bandwidth.

# Server response
ETag: "a3f4b2c1d0e9"

# Client conditional request


GET /articles/42 If-None-Match: "a3f4b2c1d0e9"

Page 7
# Server if unchanged:
HTTP/1.1 304 Not Modified

12. HATEOAS and Hypermedia

HATEOAS (Hypermedia as the Engine of Application State) is the most advanced REST constraint, and the one most
APIs skip. In a true HATEOAS API, the server sends links to related resources and available actions in each response.
Clients navigate the API by following links rather than constructing URLs.

This decouples clients from URL structure: the client only needs to know the entry point URL. All other URLs are
discovered at runtime from the responses.

{
"data": { "id": 42, "name": "Alice", "status": "active" },
"links": {
"self": { "href": "/users/42", "method": "GET" },
"update": { "href": "/users/42", "method": "PATCH" },
"delete": { "href": "/users/42", "method": "DELETE" },
"posts": { "href": "/users/42/posts", "method": "GET" },
"deactivate": { "href": "/users/42/deactivate", "method": "POST" }
}
}

13. GraphQL vs REST

GraphQL is a query language for APIs developed by Facebook. It is not a replacement for REST but an alternative with
different trade-offs:

Aspect REST GraphQL

Endpoint count One per resource Single endpoint


Data fetching Fixed response shape Client specifies fields
Over-fetching Common Avoided
Under-fetching Multiple roundtrips Single query
Caching Easy (HTTP cache) Complex (need client library)
Tooling Universal Ecosystem-dependent
Learning curve Low Medium
Best for Public APIs, simple CRUD Complex UIs, mobile apps

REST remains the default choice for most APIs. GraphQL shines when clients have highly variable data needs (e.g., a
news feed with many optional fields) or when reducing bandwidth on mobile is critical.

14. Security Checklist

Security must be considered at every layer of an API. The following checklist covers the most common vulnerabilities
and how to mitigate them.

Page 8
*

Page 9
Use HTTPS everywhere. Never transmit credentials or tokens over plain HTTP.
* Va

Common API Security Vulnerabilities (OWASP API Top 10)

ID Name Example

API1 Broken Object Level Auth GET /invoices/99 returns another user's invoice
API2 Broken Auth Weak passwords accepted, no brute-force limit
API3 Broken Object Prop Auth PATCH /users/me updates admin=true via mass ass
API4 Unrestricted Resource No pagination; GET /logs returns 1M records
API5 Broken Function Level Auth DELETE /admin/users works for non-admin token
API6 Unrestricted Access to Flows Password reset OTP never expires
API7 SSRF GET /fetch?url=[Link]
API8 Security Misconfiguration Verbose stack traces exposed in 500 responses
API9 Improper Inventory Mgmt Old v1 endpoint still exposed without auth
API10 Unsafe Consumption of APIs Trusting 3rd-party API response without validation

15. Conclusion

A well-designed REST API is intuitive, consistent, and durable. It uses HTTP verbs correctly, structures URLs around
resources, returns meaningful status codes, and communicates its contract through documentation.

The best APIs feel obvious in hindsight. Consumers can guess the URL structure, know what to expect from each
method, and handle errors gracefully. Building that kind of experience requires intentional design decisions at every
layer: URL structure, response envelopes, error formats, versioning strategy, and authentication.

Invest in API design early. Changing a public API after consumers have built on top of it is costly and painful. A strong
foundation pays dividends for years.

Page 10

You might also like