Understanding and Implementing APIs

Key Topics

  1. Definition and Importance of APIs

  2. Types of APIs

  3. RESTful API Principles

  4. API Security Best Practices

  5. Handling CORS in API Development

  6. Best Practices for API Design

  7. Error Handling Strategies

1. Summary

An API is a contract: it names the operations a system offers, the shape of the data each one accepts and returns, and the errors it can produce. Implementing one well means more than writing route handlers. It needs authentication and authorisation, input validation, consistent error responses, versioning, pagination for large collections, rate limiting, and documentation that matches the code. The key topics above list these principles; the sections below show how they fit into the request path and how they look in working code.

2. Anatomy of a request

Anatomy of an API Request ClientHTTP request GatewayTLS, rate limit AuthJWT / OAuth 2.0 Validationschema check Handlerbusiness logic Data storeDB, cache Responsestatus + JSON Each layer rejects early with a specific status code: 401/403 at auth, 422 or 400 at validation, 429 at the rate limiter.

A request passes through layers that each enforce one concern. TLS terminates at a load balancer or gateway, which may also apply rate limits and CORS rules. Authentication verifies who the caller is, typically by validating a JWT signature or an OAuth 2.0 access token; authorisation then decides whether that caller may act on the requested resource. Validation checks the body and parameters against a schema before business logic runs. Keeping each concern in its own middleware or dependency keeps handlers small and makes the rejection behaviour consistent across endpoints.

3. Choosing an API style

Choosing an API Style RESTresources + HTTP verbs GraphQLclient-shaped queries gRPCprotobuf over HTTP/2 SOAPXML + WSDL contract REST for public and CRUD APIs; GraphQL for many clients needing different shapes; gRPC for internal service-to-service calls; SOAP mainly when integrating with existing enterprise systems.
StyleStrengthsWeaknesses
RESTSimple, cacheable, universal toolingOver- or under-fetching; many round trips
GraphQLOne endpoint, clients choose fieldsCaching and rate limiting are harder; query cost control needed
gRPCCompact binary, streaming, generated clientsNot browser-native; harder to inspect by hand
SOAPFormal contracts, WS-SecurityVerbose XML, heavy tooling

4. Worked example: a small REST API

# pip install fastapi uvicorn
from fastapi import FastAPI, HTTPException, Depends, Header, Query
from pydantic import BaseModel, Field

app = FastAPI(title="Users API", version="1.0")
DB: dict[int, dict] = {}

class UserIn(BaseModel):
    name: str = Field(min_length=1, max_length=80)
    email: str

def require_token(authorization: str = Header(...)):
    if authorization != "Bearer demo-token":          # replace with real JWT validation
        raise HTTPException(status_code=401, detail="invalid token")

@app.post("/api/v1/users", status_code=201, dependencies=[Depends(require_token)])
def create_user(user: UserIn):
    uid = len(DB) + 1
    DB[uid] = {"id": uid, **user.model_dump()}
    return DB[uid]

@app.get("/api/v1/users")
def list_users(limit: int = Query(20, le=100), offset: int = 0):
    items = list(DB.values())[offset:offset + limit]
    return {"items": items, "total": len(DB), "limit": limit, "offset": offset}

@app.get("/api/v1/users/{uid}")
def get_user(uid: int):
    if uid not in DB:
        raise HTTPException(status_code=404, detail="user not found")
    return DB[uid]
uvicorn app:app --reload
curl -X POST localhost:8000/api/v1/users -H 'Authorization: Bearer demo-token' \
     -H 'Content-Type: application/json' -d '{"name":"Ada","email":"ada@example.com"}'
curl 'localhost:8000/api/v1/users?limit=10'
# interactive OpenAPI docs: http://localhost:8000/docs

The example applies the principles directly: a versioned path, resource-based URLs, a 201 status on creation, schema validation from the Pydantic model (invalid input returns 422 automatically), a reusable auth dependency, pagination with a capped limit, and generated OpenAPI documentation.

5. Status codes and error format

CodeMeaningTypical cause
200 / 201 / 204OK / Created / No ContentSuccess
400 / 422Bad request / validation failedMalformed JSON, schema violation
401 / 403Unauthenticated / forbiddenMissing token / lacks permission
404 / 409Not found / conflictUnknown ID / duplicate or version clash
429Too many requestsRate limit exceeded; include Retry-After
500 / 503Server error / unavailableBug / overload or maintenance

Return errors in one consistent JSON shape, for example {"error": {"code": "user_not_found", "message": "..."}}, so clients can branch on a stable code rather than parsing messages.

6. Pitfalls