CrackedRuby CrackedRuby

Overview

HATEOAS (Hypermedia as the Engine of Application State) represents the final constraint in REST architecture, distinguishing fully RESTful APIs from conventional HTTP APIs. The constraint mandates that servers include hypermedia links in responses, enabling clients to discover available actions dynamically rather than hardcoding API knowledge.

In a HATEOAS-compliant API, each response contains not just data but also links describing what operations the client can perform next. A client begins at a single entry point and navigates the API entirely through server-provided links, similar to how web browsers navigate HTML pages through hyperlinks. The server controls available actions by including or excluding links based on current application state.

The constraint addresses coupling between clients and servers. Traditional APIs require clients to construct URLs using domain knowledge—knowing endpoint patterns, query parameters, and HTTP methods. HATEOAS eliminates this requirement by having servers advertise available operations. When business rules change or new features appear, servers adjust the links they provide without requiring client updates.

Consider an order resource. A traditional API client constructs URLs like /orders/123/cancel based on documentation. A HATEOAS API includes links in the response:

{
  "id": 123,
  "status": "pending",
  "total": 99.99,
  "_links": {
    "self": { "href": "/orders/123" },
    "cancel": { "href": "/orders/123/cancel", "method": "DELETE" },
    "payment": { "href": "/orders/123/payment", "method": "POST" }
  }
}

When the order ships, the cancel link disappears because cancellation becomes invalid. The client requires no business logic update—it simply presents available actions based on returned links.

Key Principles

HATEOAS operates on several foundational principles that distinguish it from traditional API design.

Hypermedia controls drive state transitions. Every response includes links representing valid state transitions from the current state. The server determines which transitions are valid based on business rules, authentication, authorization, and resource state. Clients never calculate URLs or determine available operations independently.

Clients remain decoupled from URL structure. URLs become opaque identifiers rather than patterns clients must understand. The server controls all URL construction, allowing URL schemes to evolve without breaking clients. A client never concatenates strings to build URLs or interpolates identifiers into URL templates.

Self-descriptive messages provide discoverability. Each response contains sufficient information for a client to understand available actions without consulting external documentation. Links include not just URLs but also HTTP methods, media types, and semantic relationships (link relations). A client encounters a new link relation and can determine its meaning through standardized relation types or inline documentation.

The application state lives on the client. The server maintains resource state (data) but the client maintains application state (where in the workflow it currently operates). The server provides navigation options, and the client chooses which transitions to follow. This aligns with REST's stateless constraint—the server never tracks which step of a workflow a particular client has reached.

Link relations provide semantic meaning. Raw URLs convey no meaning; link relations describe what an operation accomplishes. Standard relations like self, next, prev, and edit provide universal semantics. Domain-specific relations like cancel-order or approve-request convey application-specific operations. Clients program against relations, not URLs.

Media types define hypermedia format. HATEOAS requires hypermedia-aware media types that specify how to represent links. JSON alone lacks hypermedia semantics; formats like HAL (Hypertext Application Language), JSON:API, Collection+JSON, and Siren add structured link representations. Each format defines conventions for embedding links, forms, and metadata.

Affordances limit available actions. Traditional APIs expose all endpoints regardless of current state. HATEOAS APIs expose only valid operations for the current context. An order resource provides a cancel link only when cancellation remains possible. A document resource provides an edit link only when the current user has edit permissions. The server advertises capabilities; the client discovers constraints.

Ruby Implementation

Ruby frameworks provide various approaches to implementing HATEOAS, from manual link construction to full hypermedia libraries.

Rails hypermedia implementation uses URL helpers and serializers to construct links programmatically. Rails URL helpers generate URLs without hardcoding paths:

class OrderSerializer
  def initialize(order, context)
    @order = order
    @context = context
  end

  def as_json
    {
      id: @order.id,
      status: @order.status,
      total: @order.total,
      links: build_links
    }
  end

  private

  def build_links
    links = {
      self: { href: order_path(@order), method: 'GET' }
    }

    links[:cancel] = { 
      href: cancel_order_path(@order), 
      method: 'DELETE' 
    } if @order.cancellable?

    links[:ship] = { 
      href: ship_order_path(@order), 
      method: 'POST' 
    } if @order.shippable?

    links[:refund] = { 
      href: refund_order_path(@order), 
      method: 'POST' 
    } if @order.refundable?

    links
  end

  def order_path(order)
    @context.url_for(controller: 'orders', action: 'show', id: order.id)
  end

  def cancel_order_path(order)
    @context.url_for(controller: 'orders', action: 'cancel', id: order.id)
  end
end

The serializer includes links conditionally based on business rules encoded in model methods. The order model encapsulates state transition logic:

class Order < ApplicationRecord
  def cancellable?
    ['pending', 'processing'].include?(status) && 
      created_at > 1.hour.ago
  end

  def shippable?
    status == 'paid' && items.all?(&:in_stock?)
  end

  def refundable?
    status == 'completed' && 
      completed_at > 30.days.ago
  end
end

ROAR (Resource-Oriented Architectures in Ruby) provides declarative hypermedia support with representers that define both data and link structure:

require 'roar/json/hal'

class OrderRepresenter < Roar::Decorator
  include Roar::JSON::HAL

  property :id
  property :status
  property :total

  link :self do
    "http://api.example.com/orders/#{represented.id}"
  end

  link :cancel do
    {
      href: "http://api.example.com/orders/#{represented.id}/cancel",
      method: 'DELETE'
    } if represented.cancellable?
  end

  link :items do
    "http://api.example.com/orders/#{represented.id}/items"
  end

  collection :items, extend: OrderItemRepresenter, embedded: true
end

# Controller usage
def show
  order = Order.find(params[:id])
  render json: OrderRepresenter.new(order).to_json
end

ROAR supports HAL, JSON-API, and custom hypermedia formats. The decorator pattern separates representation logic from model code, allowing multiple representations of the same resource.

Grape API with hypermedia combines the Grape framework with hypermedia gems:

class OrderAPI < Grape::API
  format :json
  
  resource :orders do
    desc 'Get an order'
    get ':id' do
      order = Order.find(params[:id])
      present order, with: OrderEntity, type: :full
    end
  end
end

class OrderEntity < Grape::Entity
  expose :id
  expose :status
  expose :total
  
  expose :links do |order, options|
    links = {
      self: { href: "/orders/#{order.id}", method: 'GET' }
    }
    
    if order.cancellable?
      links[:cancel] = { 
        href: "/orders/#{order.id}/cancel", 
        method: 'DELETE',
        title: 'Cancel this order'
      }
    end
    
    if order.status == 'pending'
      links[:payment] = {
        href: "/orders/#{order.id}/payment",
        method: 'POST',
        title: 'Submit payment'
      }
    end
    
    links
  end
end

Rails Responders with custom media types handles content negotiation and hypermedia format selection:

class ApplicationController < ActionController::API
  respond_to :json, :hal_json

  def show
    @order = Order.find(params[:id])
    respond_with @order
  end
end

# Register custom media type
Mime::Type.register 'application/hal+json', :hal_json

# Custom responder
class HalResponder < ActionController::Responder
  def to_hal_json
    controller.render json: OrderHalSerializer.new(resource).to_json
  end
end

Dynamic link generation based on abilities integrates authorization libraries:

class OrderSerializer
  def initialize(order, user)
    @order = order
    @user = user
    @ability = Ability.new(user)
  end

  def as_json
    {
      id: @order.id,
      status: @order.status,
      links: build_links
    }
  end

  private

  def build_links
    links = { self: { href: "/orders/#{@order.id}" } }

    if @ability.can?(:cancel, @order)
      links[:cancel] = { 
        href: "/orders/#{@order.id}/cancel",
        method: 'DELETE'
      }
    end

    if @ability.can?(:ship, @order)
      links[:ship] = { 
        href: "/orders/#{@order.id}/ship",
        method: 'POST'
      }
    end

    if @ability.can?(:view_tracking, @order)
      links[:tracking] = { 
        href: "/orders/#{@order.id}/tracking",
        method: 'GET'
      }
    end

    links
  end
end

Practical Examples

Basic resource with state-dependent links demonstrates how available actions change with resource state:

# Order in pending state
{
  "id": 101,
  "status": "pending",
  "total": 149.99,
  "created_at": "2025-10-07T10:00:00Z",
  "_links": {
    "self": {
      "href": "/orders/101",
      "method": "GET"
    },
    "cancel": {
      "href": "/orders/101",
      "method": "DELETE",
      "title": "Cancel this order"
    },
    "update": {
      "href": "/orders/101",
      "method": "PATCH",
      "title": "Update order details"
    },
    "payment": {
      "href": "/orders/101/payment",
      "method": "POST",
      "title": "Submit payment information"
    },
    "items": {
      "href": "/orders/101/items",
      "method": "GET",
      "title": "View order items"
    }
  }
}

# Same order after payment
{
  "id": 101,
  "status": "processing",
  "total": 149.99,
  "created_at": "2025-10-07T10:00:00Z",
  "paid_at": "2025-10-07T10:15:00Z",
  "_links": {
    "self": {
      "href": "/orders/101",
      "method": "GET"
    },
    "track": {
      "href": "/orders/101/tracking",
      "method": "GET",
      "title": "Track shipment"
    },
    "items": {
      "href": "/orders/101/items",
      "method": "GET",
      "title": "View order items"
    }
  }
}

The pending order offers cancellation and payment links. After payment, these links disappear and a tracking link appears. The client needs no business logic—it renders available actions from the links provided.

Collection resource with pagination shows hypermedia-driven navigation through result sets:

# GET /orders?page=2&per_page=10
{
  "_embedded": {
    "orders": [
      {
        "id": 201,
        "status": "completed",
        "total": 89.99,
        "_links": {
          "self": { "href": "/orders/201" }
        }
      },
      {
        "id": 202,
        "status": "pending",
        "total": 129.99,
        "_links": {
          "self": { "href": "/orders/202" }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "/orders?page=2&per_page=10"
    },
    "first": {
      "href": "/orders?page=1&per_page=10"
    },
    "prev": {
      "href": "/orders?page=1&per_page=10"
    },
    "next": {
      "href": "/orders?page=3&per_page=10"
    },
    "last": {
      "href": "/orders?page=5&per_page=10"
    }
  },
  "page": 2,
  "per_page": 10,
  "total": 47
}

Clients paginate by following next and prev links rather than constructing page URLs. When no more results exist, the next link disappears. Clients implement pagination generically without coupling to query parameter schemes.

Nested resource relationships demonstrate navigating resource hierarchies:

# GET /orders/101
{
  "id": 101,
  "status": "completed",
  "total": 149.99,
  "_links": {
    "self": { "href": "/orders/101" },
    "customer": { "href": "/customers/42" },
    "items": { "href": "/orders/101/items" },
    "invoice": { "href": "/orders/101/invoice" },
    "shipment": { "href": "/shipments/88" }
  }
}

# Following the items link: GET /orders/101/items
{
  "_embedded": {
    "items": [
      {
        "id": 301,
        "product_id": 55,
        "quantity": 2,
        "price": 49.99,
        "_links": {
          "self": { "href": "/orders/101/items/301" },
          "product": { "href": "/products/55" },
          "order": { "href": "/orders/101" }
        }
      },
      {
        "id": 302,
        "product_id": 67,
        "quantity": 1,
        "price": 99.99,
        "_links": {
          "self": { "href": "/orders/101/items/302" },
          "product": { "href": "/products/67" },
          "order": { "href": "/orders/101" }
        }
      }
    ]
  },
  "_links": {
    "self": { "href": "/orders/101/items" },
    "order": { "href": "/orders/101" }
  }
}

Each resource links to related resources, creating a navigable graph. Clients traverse relationships through links without constructing URLs.

Conditional actions with templated URLs shows form-like operations:

{
  "id": 101,
  "status": "pending",
  "_links": {
    "self": { "href": "/orders/101" },
    "search_products": {
      "href": "/products{?category,min_price,max_price}",
      "templated": true,
      "title": "Search for products to add"
    },
    "add_item": {
      "href": "/orders/101/items",
      "method": "POST",
      "title": "Add item to order"
    }
  },
  "_forms": {
    "add_item": {
      "method": "POST",
      "href": "/orders/101/items",
      "fields": [
        { "name": "product_id", "type": "number", "required": true },
        { "name": "quantity", "type": "number", "required": true }
      ]
    }
  }
}

The search_products link uses URI templates (RFC 6570) for parameterized queries. The forms section describes how to construct POST requests, enabling generic form-based clients.

Error responses with recovery links guide clients through error resolution:

# POST /orders/101/items with invalid data
# Response: 422 Unprocessable Entity
{
  "error": "Validation failed",
  "details": [
    "Product is out of stock",
    "Quantity exceeds maximum order limit"
  ],
  "_links": {
    "self": { "href": "/orders/101/items" },
    "order": { "href": "/orders/101" },
    "alternative_products": {
      "href": "/products?similar_to=55&in_stock=true",
      "title": "View similar products in stock"
    },
    "contact_support": {
      "href": "/support/requests",
      "method": "POST",
      "title": "Contact support for assistance"
    }
  }
}

Error responses include links to recovery actions. Clients can programmatically offer alternatives rather than displaying generic error messages.

Design Considerations

Complexity versus flexibility tradeoff represents the central decision in HATEOAS adoption. Fully hypermedia-driven APIs require additional server-side logic to calculate links, more complex response structures, and clients capable of interpreting hypermedia. Simple CRUD APIs with hardcoded URLs require less infrastructure but couple clients tightly to server implementation.

HATEOAS benefits systems expecting long-term evolution. When business rules change frequently, URL structures evolve, or workflow states become complex, hypermedia decouples clients from these changes. Clients continue functioning as servers add features or modify workflows. For stable, simple APIs serving known clients, the added complexity may not justify the benefits.

Client sophistication requirements determine feasibility. Generic hypermedia clients can navigate any HATEOAS API by following links and rendering available actions. Building such clients requires significant upfront investment. Most organizations build application-specific clients that understand domain semantics but rely on hypermedia for URL construction and action discovery. This middle ground provides decoupling benefits without requiring fully generic clients.

Mobile applications present particular challenges. Download size constraints discourage complex hypermedia parsing libraries. Offline operation requires caching link structures or falling back to URL construction. Native UI patterns expect direct navigation rather than discovery-based flow. Web applications handle hypermedia more naturally, mirroring browser-style navigation.

Media type selection impacts interoperability and tooling support. HAL (Hypertext Application Language) provides simple link embedding with broad tooling support. JSON:API offers comprehensive relationship modeling and sparse fieldset support. Siren includes action descriptions with form semantics. Collection+JSON focuses on collection resources with rich query capabilities.

Standardized media types enable generic clients and tooling but constrain response structures. Custom media types allow application-specific optimizations but require custom client development. Many organizations use standard media types for public APIs and custom formats for internal services.

Performance implications arise from additional response overhead. Each resource includes links alongside data, increasing payload size. Deep resource graphs with embedded links compound this overhead. Response caching becomes critical—links often remain stable across requests, allowing aggressive caching strategies.

Link calculation consumes server resources. Authorization checks, business rule evaluation, and URL generation occur for every request. Caching link structures, using lazy evaluation, or pre-computing common link patterns mitigates this cost. High-traffic APIs may limit link inclusion to essential navigation, providing detailed hypermedia only when requested.

Documentation strategy shifts focus from endpoint catalogs to workflow descriptions. Traditional API documentation lists endpoints, parameters, and response formats. HATEOAS documentation describes entry points, link relations, and state transitions. Clients need to understand available workflows, not specific URLs.

API explorers become valuable for HATEOAS APIs. Interactive tools that discover and navigate hypermedia help developers understand available actions. Generated documentation from link relation registries reduces manual documentation burden.

Versioning approaches differ from traditional API versioning. URL schemes can evolve without breaking clients since clients follow links rather than construct URLs. Link relation semantics require versioning when meanings change. Media type versions handle structural changes to hypermedia format.

Many HATEOAS APIs maintain stable link relations across versions while evolving URLs and response structures freely. Clients coupled to link relations require updates only when workflow semantics change, not when implementation details evolve.

Common Patterns

HAL (Hypertext Application Language) represents the most widely adopted hypermedia format, offering simple link embedding in JSON:

class HalSerializer
  def self.serialize(resource)
    {
      id: resource.id,
      status: resource.status,
      _links: {
        self: { href: resource_path(resource) },
        cancel: { 
          href: cancel_resource_path(resource) 
        }.compact,
        items: { href: resource_items_path(resource) }
      },
      _embedded: {
        items: resource.items.map { |item| ItemHalSerializer.serialize(item) }
      }
    }
  end
end

HAL uses reserved _links and _embedded properties. Links contain href and optional attributes like templated, type, and title. Embedded resources nest related entities with their own links, reducing round trips while maintaining hypermedia structure.

JSON:API specification provides comprehensive conventions for relationships, sparse fieldsets, and pagination:

{
  "data": {
    "type": "orders",
    "id": "101",
    "attributes": {
      "status": "pending",
      "total": 149.99
    },
    "relationships": {
      "customer": {
        "links": {
          "self": "/orders/101/relationships/customer",
          "related": "/orders/101/customer"
        },
        "data": { "type": "customers", "id": "42" }
      },
      "items": {
        "links": {
          "self": "/orders/101/relationships/items",
          "related": "/orders/101/items"
        }
      }
    },
    "links": {
      "self": "/orders/101"
    }
  },
  "included": [
    {
      "type": "customers",
      "id": "42",
      "attributes": {
        "name": "John Doe",
        "email": "john@example.com"
      }
    }
  ]
}

JSON:API separates relationship links from data inclusion, allowing clients to request related resources selectively through sparse fieldsets. The included section provides compound documents with related resources, optimizing for common access patterns.

Siren hypermedia format adds action descriptions with form semantics:

{
  "class": ["order"],
  "properties": {
    "id": 101,
    "status": "pending",
    "total": 149.99
  },
  "entities": [
    {
      "class": ["items", "collection"],
      "rel": ["/rels/order-items"],
      "href": "/orders/101/items"
    }
  ],
  "actions": [
    {
      "name": "add-item",
      "title": "Add Item",
      "method": "POST",
      "href": "/orders/101/items",
      "type": "application/json",
      "fields": [
        { "name": "product_id", "type": "number", "required": true },
        { "name": "quantity", "type": "number", "required": true }
      ]
    },
    {
      "name": "cancel-order",
      "title": "Cancel Order",
      "method": "DELETE",
      "href": "/orders/101"
    }
  ],
  "links": [
    { "rel": ["self"], "href": "/orders/101" },
    { "rel": ["customer"], "href": "/customers/42" }
  ]
}

Siren actions describe complete operation signatures including HTTP method, content type, and field schemas. Generic Siren clients can generate forms from action descriptions, enabling truly generic user interfaces.

Link relation registries provide standardized semantics for common operations. IANA maintains a registry of standard link relations:

STANDARD_RELATIONS = {
  self: 'The current resource',
  next: 'The next resource in sequence',
  prev: 'The previous resource in sequence',
  first: 'The first resource in sequence',
  last: 'The last resource in sequence',
  edit: 'An editable version of the resource',
  collection: 'A collection containing the resource'
}

CUSTOM_RELATIONS = {
  'http://api.example.com/rels/cancel': 'Cancel the order',
  'http://api.example.com/rels/ship': 'Ship the order',
  'http://api.example.com/rels/refund': 'Issue refund for the order'
}

Standard relations enable generic client behavior. Custom relations use URLs (often as link relation types) that resolve to documentation describing the relation's semantics.

State machine with hypermedia transitions models workflows as link-driven state machines:

class OrderStateMachine
  TRANSITIONS = {
    pending: [:cancel, :pay],
    paid: [:ship, :refund],
    shipped: [:deliver, :return],
    delivered: [:return],
    cancelled: [],
    refunded: []
  }

  def available_transitions(order)
    TRANSITIONS[order.status.to_sym].map do |transition|
      {
        rel: transition.to_s,
        href: send("#{transition}_order_path", order),
        method: transition_method(transition),
        title: transition_title(transition)
      }
    end
  end

  private

  def transition_method(transition)
    case transition
    when :cancel, :return then 'DELETE'
    when :pay, :ship, :deliver, :refund then 'POST'
    else 'GET'
    end
  end

  def transition_title(transition)
    transition.to_s.titleize
  end
end

The state machine defines valid transitions per state. The hypermedia layer exposes these transitions as links, ensuring clients can only attempt valid operations.

Tools & Ecosystem

ROAR (Resource-Oriented Architectures in Ruby) provides the most comprehensive Ruby hypermedia framework, supporting multiple media types and representers:

gem 'roar'
gem 'roar-rails'

# config/initializers/roar.rb
require 'roar/json/hal'

# app/representers/order_representer.rb
class OrderRepresenter < Roar::Decorator
  include Roar::JSON::HAL

  property :id
  property :status
  property :total
  property :created_at

  link :self do
    order_url(represented)
  end

  link :cancel do
    cancel_order_url(represented) if represented.cancellable?
  end

  collection :items, 
             decorator: OrderItemRepresenter, 
             embedded: true
end

ROAR separates representation from models through decorators, handles media type negotiation, and provides hypermedia-aware serialization with conditional link inclusion.

Hypermedia gem offers lightweight HAL support for Rails applications:

gem 'hypermedia'

class OrdersController < ApplicationController
  include Hypermedia::Resource

  def show
    order = Order.find(params[:id])
    
    render_resource order, {
      links: {
        self: order_path(order),
        cancel: cancel_order_path(order)
      },
      embedded: {
        items: order.items
      }
    }
  end
end

ActiveModel Serializers with HAL support integrates with existing Rails serialization patterns:

gem 'active_model_serializers'

class OrderSerializer < ActiveModel::Serializer
  attributes :id, :status, :total

  has_many :items
  belongs_to :customer

  def _links
    links = {
      self: { href: order_url(object) }
    }

    links[:cancel] = { 
      href: cancel_order_url(object) 
    } if object.cancellable?

    links
  end

  def order_url(order)
    Rails.application.routes.url_helpers.order_url(
      order, 
      host: 'api.example.com'
    )
  end
end

Grape Entity with hypermedia extensions adds hypermedia support to Grape APIs:

gem 'grape'
gem 'grape-entity'

class OrderEntity < Grape::Entity
  expose :id
  expose :status
  expose :total
  
  expose :_links do |order, options|
    {
      self: { href: "/orders/#{order.id}" },
      items: { href: "/orders/#{order.id}/items" }
    }
  end
  
  expose :_embedded do |order, options|
    {
      items: order.items.map { |i| ItemEntity.represent(i) }
    }
  end
end

Faraday hypermedia middleware enables clients to consume hypermedia APIs:

gem 'faraday'
gem 'faraday_hal_middleware'

client = Faraday.new('https://api.example.com') do |conn|
  conn.request :json
  conn.response :hal_json
  conn.adapter Faraday.default_adapter
end

response = client.get('/orders/101')
order = response.body

# Follow links programmatically
if order._links[:items]
  items_response = client.get(order._links[:items][:href])
end

# Conditional action execution
if order._links[:cancel]
  client.delete(order._links[:cancel][:href])
end

JSON:API implementation gems support the JSON:API specification:

gem 'jsonapi-resources'

class OrderResource < JSONAPI::Resource
  attributes :status, :total
  
  has_many :items
  belongs_to :customer
  
  def self.records(options = {})
    Order.includes(:items, :customer)
  end
end

# Routes
namespace :api do
  jsonapi_resources :orders
end

Reference

Standard Link Relations

Relation Description Usage
self Current resource Always include for resource identity
next Next resource in sequence Pagination, ordered collections
prev Previous resource in sequence Pagination, ordered collections
first First resource in sequence Pagination start point
last Last resource in sequence Pagination end point
edit Editable representation Modification operations
create Template for creating Form submission endpoint
collection Parent collection Navigate from item to collection
item Member of collection Navigate from collection to items
up Parent resource Hierarchical navigation
related Related resource Generic relationship link

Common Media Types

Media Type Format Key Features
application/hal+json HAL Simple link embedding, embedded resources
application/vnd.api+json JSON:API Standardized relationships, sparse fieldsets
application/vnd.siren+json Siren Action descriptions, form semantics
application/vnd.collection+json Collection+JSON Collection-focused, query templates
application/json-home JSON Home API discovery document

HTTP Methods in HATEOAS

Method Purpose Link Usage
GET Retrieve resource Navigation links, read operations
POST Create resource, actions Form submission, state transitions
PUT Replace resource Full update operations
PATCH Partial update Incremental modifications
DELETE Remove resource Deletion, cancellation operations
OPTIONS Discover capabilities Available methods for resource
HEAD Retrieve headers Existence checks, metadata

Link Attributes

Attribute Type Purpose
href string Target URL, required
method string HTTP method, defaults to GET
type string Media type of target resource
title string Human-readable link description
templated boolean Indicates URI template usage
deprecation string URL to deprecation notice
name string Secondary identifier for link
profile string URI to profile documentation
hreflang string Language of target resource

URI Template Variables

Pattern Meaning Example
{variable} Required parameter /orders/{id}
{?param} Query parameter /products{?category}
{?param1,param2} Multiple query params /search{?q,limit,offset}
{/segments} Path segments /users{/id}/orders
{.format} File extension /report{.format}
{#fragment} Fragment identifier /doc{#section}

Response Codes for Hypermedia

Code Usage When to Include Links
200 OK Successful retrieval Full hypermedia controls
201 Created Resource created Location header, self link
202 Accepted Async processing started Status polling link
301 Moved Permanently Permanent redirect New resource location
303 See Other Result elsewhere Result resource link
400 Bad Request Invalid input Form resubmission link
401 Unauthorized Authentication required Login link
403 Forbidden Insufficient permissions Available alternatives
404 Not Found Resource not found Collection or search link
422 Unprocessable Entity Validation failed Correction form link

HAL Format Structure

Element Location Purpose
_links Root object Navigation links
_embedded Root object Nested resources with own links
href Link object Target URL
templated Link object URI template indicator
type Link object Target media type
title Link object Link description

JSON:API Format Elements

Element Purpose Structure
data Primary resource Object or array with type, id, attributes
relationships Related resources Links to relationships and related resources
included Compound documents Array of related resource objects
links Navigation Self, related, pagination links
meta Metadata Non-standard information

Siren Format Elements

Element Purpose Contents
class Resource classification Array of semantic classifiers
properties Resource state Object with resource attributes
entities Sub-entities Embedded or linked related resources
actions Available operations Operation descriptions with fields
links Navigation Array of link objects
title Resource title Human-readable identifier