GenAIHub
← Back to Technical Section

REST API

Architecture Standard

Representational 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.

Stateless

No server-side session

Cacheable

Built-in cache support

Uniform

Consistent interface

Layered

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

  • 200 OK — Request succeeded
  • 201 Created — Resource created
  • 204 No Content — Success, no body

4xx — Client Errors

  • 400 Bad Request — Invalid input
  • 401 Unauthorized — Auth required
  • 403 Forbidden — No permission
  • 404 Not Found — Resource missing
  • 429 Too Many Requests — Rate limited

3xx — Redirects

  • 301 Moved Permanently
  • 304 Not Modified (cached)

5xx — Server Errors

  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service 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
Use Plurals

/users not /user

Use Kebab-Case

/user-profiles not /userProfiles

Version Your API

/api/v1/ or header-based versioning

Request & Response Examples

POST Create a Resource

# Request
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"
}
# Response (201 Created)
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

# Response (200 OK)
{
    "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 /users not GET /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/limit or 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 Requests with Retry-After header.
  • 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