Skip to content

HATEOAS Actions and Forms — Guiding Clients Through State Transitions

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about HATEOAS Actions and Forms. We cover key concepts, practical examples, and best practices to help you master this topic.

HATEOAS actions and forms extend hypermedia links by describing not just where to go but what data to send, enabling clients to perform state transitions without prior knowledge.

What You'll Learn

  • How actions describe available operations
  • The concept of hypermedia forms
  • Implementing action-driven state machines

Why It Matters

Forms make APIs truly self-documenting. A client can discover all available operations and their input requirements at runtime, no documentation needed.

stateDiagram-v2
    [*] --> Pending: Create Order
    Pending --> Paid: POST /payments {amount}
    Pending --> Cancelled: DELETE /orders/123
    Paid --> Shipped: POST /shipments {address}
    Shipped --> Delivered: POST /confirm
    Delivered --> [*]

Code Examples

// HATEOAS response with actions
{
  "order_id": "ORD-123",
  "status": "pending",
  "total": 2999,
  "_actions": {
    "pay": {
      "method": "POST",
      "href": "/orders/ORD-123/payments",
      "fields": [
        {"name": "amount", "type": "number", "required": true},
        {"name": "currency", "type": "text", "default": "USD"}
      ]
    },
    "cancel": {
      "method": "DELETE",
      "href": "/orders/ORD-123"
    }
  }
}
# Client discovering and executing actions
order = get_order("ORD-123")

if "pay" in order.get("_actions", {}):
    pay_action = order["_actions"]["pay"]
    payload = {field["name"]: order["total"] for field in pay_action["fields"]}
    response = requests.post(
        f"{BASE}{pay_action['href']}",
        json=payload
    )
    print(f"Payment: {response.status_code}")

Common Mistakes

1. Showing Actions for Invalid States

A paid order shouldn't show a "pay" action. Actions must reflect current state.

2. Not Including Required Fields

Every action should document which fields are required and their types.

3. Hardcoding Actions on the Client

Clients should read _actions from the response, not hardcode them.

Links navigate; actions change state. Keep them conceptually separate.

5. Forgetting to Update Actions After Transitions

After payment, the order response should show new available actions.

Practice Questions

  1. How do actions differ from links in HATEOAS?
  2. What information should an action include besides the URL?
  3. Why should actions change based on resource state?
  4. How do fields in an action help clients?
  5. Can an action point to a different resource than the current one?

Answers:

  1. Actions change resource state; links navigate to related resources.
  2. HTTP method, URL, and field definitions (name, type, required).
  3. Different states have different legal transitions.
  4. Fields tell clients what data to send, like a form template.
  5. Yes. Paying an order might POST to /payments, a different resource.

Challenge: Design a state machine for a blog post with states (draft, published, archived). Show which actions are available in each state with their required fields.

FAQ

Are HATEOAS actions the same as HTML forms?

: Conceptually yes. HATEOAS actions are like HTML forms but for API responses.

Do all HATEOAS formats support actions?

: No. HAL only supports links. Siren and Collection+JSON support actions/forms.

Can I combine links and actions in one response?

: Yes. Links for navigation, actions for state-changing operations.

What's Next

Learn about Dynamic Discovery in HATEOAS, then explore HATEOAS Clients for consuming hypermedia APIs.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro