Community RESTful HATEOAS Best Practices
Comprehensive guide to building REST APIs that reach the Glory of REST (Richardson Maturity Level 3) in Ruby on Rails. Contains 47 rules across 9 categories, ordered by the request/response lifecycle — from resource URI design through hypermedia link relations to API evolution.
When to Apply
Reference these guidelines when:
- Designing new REST API endpoints and resource URIs
- Adding hypermedia controls (_links, affordances) to API responses
- Implementing content negotiation with HAL, JSON:API, or vendor media types
- Building paginated, filterable, sortable collection endpoints
- Reviewing APIs for proper HTTP method semantics and status codes
- Evolving APIs without breaking existing clients
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Resource Modeling | CRITICAL | res- |
| 2 | HTTP Method Semantics | CRITICAL | http- |
| 3 | Hypermedia & Link Relations | CRITICAL | link- |
| 4 | Status Codes & Response Headers | HIGH | status- |
| 5 | Content Negotiation & Media Types | HIGH | media- |
| 6 | Collection Patterns | MEDIUM-HIGH | coll- |
| 7 | Error Semantics | MEDIUM | err- |
| 8 | Caching & Conditional Requests | MEDIUM | cache- |
| 9 | API Evolution | LOW-MEDIUM | evolve- |
Quick Reference
1. Resource Modeling (CRITICAL)
res-noun-based-uris- URIs must be nouns, not verbsres-plural-collection-uris- Always use plural nouns for collectionsres-limit-nesting-depth- Limit nested resources to max 2 levelsres-model-business-entities- Model business entities, not database tablesres-use-consistent-identifiers- Use opaque identifiers, never auto-increment IDsres-sub-resources-for-relationships- Express relationships as sub-resources
2. HTTP Method Semantics (CRITICAL)
http-get-must-be-safe- Keep GET requests free of side effectshttp-post-for-creation- Return 201 Created with Location header from POSThttp-put-for-full-replacement- Use PUT only for full resource replacementhttp-patch-for-partial-updates- PATCH for partial updates with merge semanticshttp-delete-is-idempotent- Ensure DELETE is idempotenthttp-head-for-metadata- Use HEAD for metadata without body transferhttp-idempotency-key- Use idempotency keys for safe POST retries
3. Hypermedia & Link Relations (CRITICAL)
link-self-link-every-resource- Include a self link in every resourcelink-related-resource-links- Link to related resources instead of foreign keyslink-action-affordances- Expose available actions as conditional linkslink-standard-relation-types- Use IANA-registered link relation typeslink-entry-point- Provide a root API entry pointlink-pagination-links- Use hypermedia links for paginationlink-embedded-vs-linked- Choose between embedding and linking
4. Status Codes & Response Headers (HIGH)
status-201-with-location- Return 201 Created with Location headerstatus-204-for-no-content- Return 204 No Content for empty responsesstatus-409-for-conflicts- Return 409 Conflict for state conflictsstatus-202-for-async- Return 202 Accepted for async operationsstatus-allow-header-on-405- Return 405 with Allow header for wrong methodsstatus-rate-limit-headers- Include rate limit headers in API responses
5. Content Negotiation & Media Types (HIGH)
media-accept-header-negotiation- Respect the Accept header for content negotiationmedia-content-type-in-responses- Set the correct Content-Type in every responsemedia-vendor-media-types- Use vendor media types for API versioningmedia-406-for-unsupported-types- Return 406 for unsupported media types
6. Collection Patterns (MEDIUM-HIGH)
coll-cursor-pagination- Use cursor-based pagination instead of offsetcoll-link-header-pagination- Include pagination links in body and Link headercoll-filtering-via-query-params- Support filtering via typed query parameterscoll-sorting-convention- Support sorting with a standardized sort parametercoll-field-selection- Support sparse fieldsets via fields parameter
7. Error Semantics (MEDIUM)
err-problem-details- Use Problem Details (RFC 9457) for errorserr-validation-errors- Return structured validation errorserr-error-links- Include recovery links in error responseserr-machine-readable-codes- Use machine-readable error codeserr-auth-error-codes- Distinguish 401 Unauthorized from 403 Forbidden
8. Caching & Conditional Requests (MEDIUM)
cache-etag-conditional-get- Use ETags with stale? for conditional GETcache-last-modified- Set Last-Modified for time-based validationcache-cache-control-headers- Set explicit Cache-Control headerscache-vary-header- Include Vary header for content-dependent caching
9. API Evolution (LOW-MEDIUM)
evolve-additive-changes-only- Make only additive changes to responsesevolve-deprecation-headers- Use Deprecation and Sunset headersevolve-hateoas-reduces-versioning- Leverage HATEOAS to eliminate URL versioning
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions - Category structure and impact levels
- Rule template - Template for adding new rules
Reference Files
| File | Description | |------|-------------| | references/_sections.md | Category definitions and ordering | | assets/templates/_template.md | Template for new rules | | metadata.json | Version and reference information |