Editorial illustration: API Response Structure Patterns: When HAL, JSON:API, and HATEOAS Actually Matter

API Design · REST · HATEOAS · HAL · JSON:API · API Response Patterns · Hypermedia

API Response Structure Patterns: When HAL, JSON:API, and HATEOAS Actually Matter

A practical guide to choosing between simple JSON envelopes, HAL, JSON:API, and HATEOAS for small teams building APIs. Understand the trade-offs, not the hype.

Published:

The Short Answer

For most indie projects and small teams, a clean, consistent JSON envelope is the right choice. HATEOAS, HAL, and JSON:API are not wrong — they solve real problems — but they add complexity that rarely pays off until your API has multiple consumers, a long lifecycle, and a team that can sustain the overhead. If you are building a single-product API for your own frontend or a small partner integration, standardize your response shape and move on.

Why Response Structure Matters More Than You Think

Every API response is a contract. When that contract changes shape from endpoint to endpoint, consumers pay a tax: extra parsing logic, fragile error handling, and documentation that drifts from reality. The most common failure mode is not a missing feature but inconsistency — one endpoint returns data inside a data key, another returns it flat, and errors appear as strings in some places and objects in others.

Leading platforms avoid this by enforcing a uniform response structure. Stripe, Google Cloud APIs, and GitHub all follow predictable patterns so clients can write generic integration code once and reuse it everywhere. The lesson for small teams is simple: decide on a response shape early, document it, and stick to it.

The Three Patterns You Should Know About

1. Simple JSON Envelope

A JSON envelope wraps your resource data inside a predictable structure. A typical success response looks like this:

{
  "status": "success",
  "data": {
    "id": "order_12345",
    "amount": 2500,
    "customer_id": "cust_789"
  }
}

And an error response follows the same shape:

{
  "status": "error",
  "error": {
    "code": "PAYMENT_FAILED",
    "message": "Payment was declined by the issuer"
  }
}

This is what most small APIs should aim for. The structure is easy to parse, easy to document, and easy to test. You gain predictability without adding a layer of hypermedia navigation.

2. HAL (Hypertext Application Language)

HAL is a JSON-based format that adds a _links section to every resource representation. It was designed to make REST APIs more discoverable by embedding navigation links directly in responses. A HAL response for an order looks like this:

{
  "_links": {
    "self": { "href": "/orders/123" },
    "customer": { "href": "/customers/789" },
    "next": { "href": "/orders?cursor=abc" }
  },
  "_embedded": {
    "customer": {
      "id": "cust_789",
      "name": "Acme Corp"
    }
  },
  "id": "order_12345",
  "amount": 2500
}

The _links section acts as a navigation table. Instead of hard-coding URLs like /customers/17/orders in your client code, the client reads the customer relation from _links and follows it. This reduces client-server coupling because the server controls the target URI behind each relation, and both sides can evolve more independently.

HAL also supports embedded resources through _embedded, which lets you nest related data in a single response instead of making multiple round trips. This is useful when you know your clients will always need the related resource together with the parent.

Frameworks like Spring HATEOAS make it straightforward to produce HAL responses. By default, Spring Boot serializes models into application/hal+json when the client sends an Accept header for that media type. You can also configure it to return HAL by default for all JSON responses, or disable that behavior with spring.hateoas.use-hal-as-default-json-media-type=false.

3. HATEOAS (Hypermedia as the Engine of Application State)

HATEOAS is often confused with HAL, but they are not the same thing. HAL is a format. HATEOAS is an architectural constraint of REST that says clients should interact with an application solely through hypermedia provided by the server. In a HATEOAS-compliant API, each response identifies related resources and currently valid state transitions through link relations.

The key insight is that the client does not need prior knowledge of every endpoint URI. It starts from an entry point, understands the media type, and discovers subsequent interactions dynamically through the links in each response. For example, an order response might include relations for self, cancel_order, and track_shipment. The client chooses an available relation instead of constructing the next URL itself.

This approach has real benefits for API evolvability. When you add a new state transition or change an endpoint path, you only need to update the links in the response. Clients that follow HATEOAS will discover the change automatically. Clients that hard-code URLs will break.

Spring Boot 3.5.4 and Spring HATEOAS support HAL-FORMS, which extends HAL with affordances — representations of forms that describe how to perform actions like creating or updating resources. This makes the API even more self-descriptive, because the client can see not just what links exist but what inputs each action requires.

4. JSON:API

JSON:API is a specification that defines a strict structure for how data should be serialized and deserialized. It requires a specific top-level shape with data, errors, meta, and links keys. It also defines rules for filtering, sorting, pagination, and relationship inclusion through query parameters like ?include=customer.

JSON:API is the most opinionated of the three patterns. It forces consistency but also forces you to conform to its conventions. This can be a strength when you have many consumers who need a predictable contract, but it can feel heavyweight for a small API with a single consumer.

When to Use Each Pattern

Use a Simple JSON Envelope When:

A consistent JSON envelope with clear success and error shapes is enough for most indie projects. The predictability you gain from standardization is worth more than the discoverability you would get from hypermedia links.

Use HAL When:

HAL gives you discoverability with relatively low overhead. The _links and _embedded sections add structure without requiring clients to understand a full specification.

Use HATEOAS When:

HATEOAS shines in long-lived, multi-consumer APIs where the cost of hard-coded URLs becomes painful. It is less useful for a small team building a single product API.

Use JSON:API When:

The Trade-Offs You Should Not Ignore

Every response structure pattern involves a trade-off between predictability and flexibility, between simplicity and discoverability.

A simple JSON envelope is predictable but not self-descriptive. Clients must know the endpoint structure in advance. HAL adds discoverability but requires clients to understand link relations and the _links / _embedded structure. HATEOAS adds full navigability but requires clients to be hypermedia-aware, which many mobile and script-based consumers are not. JSON:API adds the most structure and the most learning curve.

There is also a maintenance cost. Hypermedia formats require your backend to generate and maintain link relations, handle recursion in bidirectional relationships, and ensure that affordances stay in sync with your business logic. If your team is two or three people, that maintenance burden is real.

A Practical Recommendation

Start with a simple, consistent JSON envelope. Define your success and error shapes, document them, and enforce them with a style guide or linter. If your API grows and you find that consumers are constantly hard-coding URLs that break when you refactor, that is the signal to add HAL links. If you then find that clients need to discover valid state transitions dynamically, that is the signal to move toward HATEOAS.

Do not adopt a hypermedia format because it is trendy. Adopt it because you have a specific problem that it solves better than a simpler alternative. The best API response structure is the one your team can maintain consistently over time.

FAQ

Is HATEOAS required for a REST API to be truly RESTful?

Technically yes — HATEOAS is one of the six constraints in Roy Fielding’s original REST thesis. In practice, most APIs called REST do not implement it, and that does not make them useless. It makes them simpler. If your API works for your consumers, the architectural purity debate is academic.

Can I mix HAL links with a simple JSON envelope?

Yes. You can start with a plain JSON response and add a _links section to specific endpoints that benefit from discoverability. This incremental approach lets you adopt hypermedia where it adds value without restructuring your entire API.

Does HATEOAS slow down API responses?

Not significantly. The additional link data is small — usually a few hundred bytes per response. The real cost is in development time, not response size. Generating and maintaining link relations requires extra code and testing.

Should mobile apps use HATEOAS?

Generally no. Mobile clients tend to prefer predictable, flat responses that are easy to parse and cache. HATEOAS adds complexity that mobile teams often do not need. A well-structured JSON envelope with clear endpoint documentation is usually the better choice for mobile consumers.

What is the difference between HAL and JSON:API?

HAL is a lightweight format focused on links and embedded resources. JSON:API is a comprehensive specification that covers serialization, filtering, sorting, pagination, and error handling. HAL is easier to adopt incrementally. JSON:API is more rigid but more powerful for complex querying.

Sources