REST API
Architecture StandardRepresentational State Transfer — the foundational architectural style for designing scalable, stateless web APIs that power the modern internet.
What is a REST API?
A REST API (Representational State Transfer Application Programming Interface) is a web service that follows the REST architectural style, defined by Roy Fielding in his 2000 doctoral dissertation. REST APIs use standard HTTP methods to perform operations on resources identified by URIs (Uniform Resource Identifiers), returning data in formats like JSON or XML.
REST has become the dominant architectural style for web APIs, powering everything from social media platforms to AI model serving endpoints. Its simplicity, scalability, and compatibility with HTTP make it the first choice for most web service implementations.
Key Principle: REST treats everything as a resource. Each resource has a unique URI, and clients interact with resources using standard HTTP methods (GET, POST, PUT, DELETE) — making APIs intuitive and predictable.
No server-side session
Built-in cache support
Consistent interface
Proxy & gateway support
The 6 REST Constraints
Roy Fielding defined six architectural constraints that a system must satisfy to be considered RESTful. These constraints work together to create scalable, maintainable, and performant APIs.
1. Client-Server
Separation of concerns between the user interface (client) and data storage (server). The client handles presentation, the server handles logic and persistence — allowing them to evolve independently.
2. Stateless
Each request from client to server must contain all the information needed to understand the request. The server stores no session state — enabling horizontal scaling and fault tolerance.
3. Cacheable
Responses must define themselves as cacheable or non-cacheable. Proper caching eliminates redundant interactions, improving performance and scalability through HTTP cache headers.
4. Uniform Interface
The fundamental REST constraint. Resources are identified by URIs, manipulated through representations, use self-descriptive messages, and leverage HATEOAS (Hypermedia as the Engine of Application State).
5. Layered System
The architecture can be composed of hierarchical layers (load balancers, API gateways, caches, servers). Each layer only interacts with the adjacent layer, enabling security and scalability.
6. Code on Demand (Optional)
Servers can extend client functionality by transferring executable code (e.g., JavaScript). This is the only optional constraint and is rarely used in modern REST APIs.
HTTP Methods & CRUD Operations
REST APIs map standard HTTP methods to CRUD (Create, Read, Update, Delete) operations. Each method has specific semantics regarding safety and idempotency.
| Method | CRUD | Example | Safe | Idempotent |
|---|---|---|---|---|
| GET | Read | GET /api/users/42 | Yes | Yes |
| POST | Create | POST /api/users | No | No |
| PUT | Update (full) | PUT /api/users/42 | No | Yes |
| PATCH | Update (partial) | PATCH /api/users/42 | No | No |
| DELETE | Delete | DELETE /api/users/42 | No | Yes |
Safe vs Idempotent: A safe method doesn't modify data (GET). An idempotent method produces the same result regardless of how many times it's called (GET, PUT, DELETE). POST is neither — calling it twice creates two resources.
HTTP Status Codes
REST APIs communicate the result of each request through standardized HTTP status codes, grouped into five classes.
2xx — Success
200OK — Request succeeded201Created — Resource created204No Content — Success, no body
4xx — Client Errors
400Bad Request — Invalid input401Unauthorized — Auth required403Forbidden — No permission404Not Found — Resource missing429Too Many Requests — Rate limited
3xx — Redirects
301Moved Permanently304Not Modified (cached)
5xx — Server Errors
500Internal Server Error502Bad Gateway503Service Unavailable
Resource Design & URL Patterns
Well-designed REST APIs follow consistent naming conventions for resources and endpoints. URIs should be intuitive, hierarchical, and use nouns (not verbs).
URL Design Rules
# Good: Use nouns (resources) GET /api/v1/users # List users GET /api/v1/users/42 # Get user 42 POST /api/v1/users # Create user PUT /api/v1/users/42 # Update user 42 DELETE /api/v1/users/42 # Delete user 42 # Nested resources (relationships) GET /api/v1/users/42/posts # Posts by user 42 GET /api/v1/users/42/posts/7 # Post 7 of user 42 # Filtering, sorting, pagination GET /api/v1/users?role=admin&sort=name&page=2&limit=20 # Bad: Avoid verbs in URLs GET /api/v1/getUser/42 # Don't do this POST /api/v1/createUser # Don't do this POST /api/v1/deleteUser/42 # Don't do this
/users not /user
/user-profiles not /userProfiles
/api/v1/ or header-based versioning
Request & Response Examples
POST Create a Resource
POST /api/v1/users HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer eyJhbGciOi... { "name": "Alice Johnson", "email": "alice@example.com", "role": "developer" }
HTTP/1.1 201 Created Content-Type: application/json Location: /api/v1/users/143 { "id": 143, "name": "Alice Johnson", "email": "alice@example.com", "role": "developer", "created_at": "2025-01-28T10:30:00Z", "_links": { "self": "/api/v1/users/143", "posts": "/api/v1/users/143/posts" } }
GET List with Pagination
{
"data": [
{"id": 1, "name": "Alice", "role": "developer"},
{"id": 2, "name": "Bob", "role": "designer"}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 142,
"total_pages": 8
},
"_links": {
"self": "/api/v1/users?page=1",
"next": "/api/v1/users?page=2",
"last": "/api/v1/users?page=8"
}
}
Authentication & Security
Since REST is stateless, each request must carry its own authentication credentials. Common patterns include:
API Key
Simple, good for server-to-server. Sent via header or query parameter.
Authorization: Api-Key sk-abc123...
# or
GET /api/data?api_key=sk-abc123...
Bearer Token (JWT)
Most common for web/mobile apps. Self-contained tokens with claims.
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
OAuth 2.0
Industry standard for delegated authorization. Supports multiple grant types.
POST /oauth/token grant_type=client_credentials &client_id=...&client_secret=...
Basic Auth
Simple username:password encoded in Base64. Only use over HTTPS.
Authorization: Basic dXNlcjpwYXNz...
Security Best Practices: Always use HTTPS, implement rate limiting (429), validate all inputs, use short-lived tokens, include CORS headers, and never expose sensitive data in URLs.
REST APIs in AI & GenAI
REST APIs are the primary interface for consuming AI and GenAI services. From OpenAI to Anthropic, every major AI provider exposes their models through REST endpoints.
LLM Chat Completion API
POST /v1/chat/completions { "model": "gpt-4", "messages": [ {"role": "user", "content": "Explain REST"} ], "temperature": 0.7 }
Embedding API
POST /v1/embeddings { "model": "text-embedding-3-large", "input": "REST API design" } // Response: 3072-dim vector {"data": [{"embedding": [0.023, ...]}]}
AI API Patterns: Most AI REST APIs follow OpenAI's pattern: POST /v1/{resource} with JSON body, Bearer token auth, and streaming via Server-Sent Events (SSE). This has become the de facto standard.
Building a REST API (Python)
FastAPI Implementation
from fastapi import FastAPI, HTTPException, Query from pydantic import BaseModel, EmailStr from typing import Optional app = FastAPI(title="Users API", version="1.0") # Models class UserCreate(BaseModel): name: str email: EmailStr role: str = "user" class UserResponse(BaseModel): id: int name: str email: str role: str # Endpoints @app.get("/api/v1/users", response_model=list[UserResponse]) async def list_users( page: int = Query(1, ge=1), limit: int = Query(20, le=100) ): return get_users(page=page, limit=limit) @app.post("/api/v1/users", response_model=UserResponse, status_code=201) async def create_user(user: UserCreate): return save_user(user) @app.get("/api/v1/users/{user_id}", response_model=UserResponse) async def get_user(user_id: int): user = find_user(user_id) if not user: raise HTTPException(status_code=404, detail="User not found") return user @app.delete("/api/v1/users/{user_id}", status_code=204) async def delete_user(user_id: int): delete_user_by_id(user_id)
Consuming a REST API (Python)
import requests import httpx # async alternative # Sync with requests response = requests.get( "https://api.example.com/v1/users", headers={"Authorization": "Bearer token..."}, params={"page": 1, "limit": 20} ) users = response.json() # Async with httpx async with httpx.AsyncClient() as client: response = await client.post( "https://api.example.com/v1/users", json={"name": "Alice", "email": "alice@ex.com"}, headers={"Authorization": "Bearer token..."} ) new_user = response.json()
REST vs Alternatives
| Feature | REST | GraphQL | gRPC | WebSocket |
|---|---|---|---|---|
| Protocol | HTTP/1.1+ | HTTP/1.1+ | HTTP/2 | WS/WSS |
| Data Format | JSON/XML | JSON | Protobuf (binary) | Any |
| Performance | Good | Good | Excellent | Real-time |
| Flexibility | Fixed endpoints | Client-driven queries | Schema-defined | Bidirectional |
| Caching | HTTP native | Complex | Custom | N/A |
| Best For | Public APIs, CRUD | Complex queries, mobile | Microservices, high-perf | Chat, streaming, live |
Error Handling Best Practices
Consistent error responses make APIs easier to consume and debug. Follow a standard error format across all endpoints.
Standard Error Response Format
HTTP/1.1 422 Unprocessable Entity { "error": { "code": "VALIDATION_ERROR", "message": "Invalid request data", "details": [ { "field": "email", "message": "Must be a valid email address", "value": "not-an-email" } ], "request_id": "req_abc123", "docs": "https://docs.api.com/errors#VALIDATION_ERROR" } }
Best Practices
-
Use nouns for resources, HTTP methods for actions:
GET /usersnotGET /getUsers. Let the HTTP method convey the action. -
Version your API from day one: Use URL versioning (
/v1/) or header-based versioning to allow backward-compatible evolution. -
Implement pagination for lists: Never return unbounded results. Use
page/limitor cursor-based pagination for large datasets. - Return appropriate status codes: Don't always return 200. Use 201 for creation, 204 for deletion, 404 for not found, 422 for validation errors.
- Use consistent error format: Include error code, message, details, and request_id in every error response for debuggability.
-
Add rate limiting and throttling: Protect your API from abuse. Return
429 Too Many RequestswithRetry-Afterheader. - Document with OpenAPI/Swagger: Use auto-generated docs (FastAPI does this natively) or hand-crafted OpenAPI specs.
Documentation & Testing Tools
OpenAPI / Swagger
Industry-standard specification for describing REST APIs. Swagger UI and ReDoc generate interactive documentation from OpenAPI specs.
Postman / Insomnia
GUI tools for testing REST APIs. Create request collections, automate tests, mock servers, and share API documentation with teams.
curl / httpie
Command-line HTTP clients. curl is ubiquitous; httpie offers a more human-friendly syntax with colored output.
Learn More
Related Topics
Test Your Knowledge
Score 8/10 or higher to pass
You need to be logged in to take this quiz.
Login to Continue