Core REST Principles
REST is defined by a set of architectural constraints rather than a formal protocol. The key constraints that matter in practice are: the client-server separation, where the API and the client are independent and communicate only through the API interface; statelessness, where each request contains all the information necessary to process it and the server does not store client session state between requests; a uniform interface, where resources are identified by URLs, operations use standard HTTP methods, and responses represent the resource state in a consistent format (typically JSON); and layerability, where the architecture allows caching, load balancing, and proxies to operate transparently between client and server. In practice, most what-the-industry-calls REST APIs are more precisely REST-adjacent: they use HTTP methods and JSON, but do not rigorously follow all REST constraints. This is fine. The important thing is consistency, not purity.
HTTP Methods and Their Correct Use
The core of REST API design is using the right HTTP method for the right operation. GET retrieves a resource without modifying it. It must be safe (no side effects) and idempotent (calling it multiple times produces the same result). GET requests can be cached. POST creates a new resource or triggers an action. It is neither safe nor idempotent. Use POST for creating resources (POST /documents creates a new document) and for actions that do not map cleanly to CRUD (POST /documents/:id/analyse triggers AI analysis). PUT replaces a resource entirely with the provided representation. It is idempotent: calling PUT with the same data multiple times produces the same result. PATCH applies a partial update to a resource, modifying only the specified fields. It is appropriate for updating one or two fields without sending the entire resource. DELETE removes a resource. It is idempotent. Using the wrong HTTP method is one of the most common REST API design mistakes. Using POST for everything, or using GET for operations that have side effects, breaks caching and client expectations.
Resource Naming and URL Design
Good REST URL design uses nouns for resource names, not verbs. The operation is expressed by the HTTP method, not the URL. Instead of POST /createDocument, use POST /documents. Instead of GET /getDocumentById?id=123, use GET /documents/123. Resources are plural nouns. Nested resources represent relationships: GET /documents/123/pages retrieves all pages of document 123. POST /documents/123/pages adds a page to document 123. Keep nesting shallow. Two levels of nesting (/resources/:id/sub-resources) is typically the practical maximum before URLs become unwieldy and hard to cache. For actions that do not fit the CRUD model, use a sub-resource noun that represents the action outcome: POST /documents/123/analysis triggers analysis and creates an analysis resource. This is more RESTful than POST /documents/123/analyse. For AI products, resources include the entities your product manages (documents, projects, reports, jobs) and the AI operations your product performs (analyses, summaries, embeddings, classifications).
Response Design and Error Handling
Consistent response design is as important as consistent URL design. Use HTTP status codes correctly: 200 for successful GET and PATCH, 201 for successful POST that creates a resource, 204 for successful DELETE with no response body, 400 for client errors (invalid input, missing required fields), 401 for unauthenticated requests, 403 for authenticated but unauthorised requests, 404 for resources that do not exist, 409 for conflicts, 422 for validation errors, 429 for rate limit exceeded, and 500 for server errors. Error responses should include a consistent JSON body with a machine-readable error code and a human-readable message. A common pattern is: error code, a string identifier like validation_error or rate_limit_exceeded; message, a human-readable description; and details, an array of specific field-level errors for validation failures. Inconsistent error formats are one of the most frustrating aspects of working with third-party APIs. Invest in getting this right from the start.
Authentication and Rate Limiting
Every REST API for an AI product needs authentication and rate limiting configured from day one. Authentication is most commonly implemented with Bearer tokens: the client includes an Authorization: Bearer <token> header with every request, and the server validates the token against the database or a JWT signature. API keys (long-lived tokens for programmatic access) and OAuth 2.0 (for delegated access where users authorise third-party integrations) are the two main authentication models for AI product APIs. Rate limiting prevents abuse and protects against runaway costs (particularly important when API calls trigger LLM inference). Implement rate limits at the authenticated user or API key level, not just at the IP address level (which is easy to bypass and affects legitimate users behind shared IPs). Return HTTP 429 with a Retry-After header when limits are exceeded. For AI products, consider a tiered rate limit: lower limits for free tier users, higher limits for paid users, with clear documentation of what each tier allows.
REST API Documentation and Developer Experience
A well-designed REST API with poor documentation is difficult to adopt. For AI products with third-party integrations or developer users, API documentation is a product in itself. The standard for REST API documentation is OpenAPI specification (formerly Swagger), which generates interactive documentation that developers can use to explore and test the API. Tools like Swagger UI, Redoc, and Scalar render OpenAPI specifications as readable, browsable documentation with code examples. Documenting every endpoint with request parameters, response schemas, authentication requirements, and example request and response bodies is the minimum for a developer-facing API. Adding code examples in the most common languages (JavaScript/TypeScript, Python, cURL) significantly reduces integration effort for developers. For AI products, documenting the AI-specific behaviour, what inputs produce better outputs, what the rate limits mean in practice, how to handle streaming responses, makes the API genuinely useful rather than just technically accessible.