skip to content

HAL, JSON:API, and Hypermedia Formats

The concrete media types that standardize hypermedia responses: HAL's _links/_embedded, JSON:API's data/relationships/included, and Siren's actions. Interviewers ask for an overview to see if you can pick a format rather than invent an ad-hoc one.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

4

Describe how a HAL document (media type application/hal+json) is laid out. What do the reserved _links and _embedded properties hold, and what problem does _embedded solve?

level: middleimportance: should knowfreq 38%

answer

  1. resource = your JSON + _links + _embedded
  2. link object: href, templated, type, name, title, deprecation
  3. _embedded kills N+1, may be partial representations
  4. one object or an array - normalise on read
  5. curies compress custom rel URIs; no actions in plain HAL

basics

~20 s

A HAL resource is ordinary JSON plus two reserved keys. _links maps relation names to link objects with an href (optionally templated, type, title). _embedded maps relation names to full nested resources, so a client gets related data in one response instead of following every link.

solid answer

~50 s

HAL is deliberately minimal: a resource object is your own properties plus two reserved members. _links is a map from relation name to a link object or an array of link objects. A link object has href and optional templated, type, name, title, deprecation. Every resource should carry a self link. _embedded is a map from relation name to resource objects - full HAL resources, recursively, with their own _links. It exists to kill the N+1 problem: rather than returning a list of order links and forcing twenty follow-up requests, the collection embeds the orders themselves. The relation names in _embedded and _links mean the same thing; embedding is a transport optimisation, not a different relationship. The practical gotchas: any relation may be a single object or an array, so clients must normalise; custom relations are URIs, shortened via a curies link; and HAL has no notion of methods or forms - it tells you where to go, not how to submit a change.

code

json · 16 lines
json
{
  "count": 2,
  "_links": {
    "self":   { "href": "/orders?page=1" },
    "next":   { "href": "/orders?page=2" },
    "curies": [ { "name": "ex", "href": "https://example.com/rels/{rel}", "templated": true } ]
  },
  "_embedded": {
    "item": [
      { "id": "42", "total": 19.99,
        "_links": { "self": {"href":"/orders/42"}, "ex:cancel": {"href":"/orders/42/cancel"} } },
      { "id": "43", "total": 5.00,
        "_links": { "self": {"href":"/orders/43"} } }
    ]
  }
}

go deeper

for a junior

Describe the two reserved members, name href and self, and say _embedded includes related resources inline to save requests.

for a middle

Add link-object options, the single-versus-array pitfall, curies for custom relations, and that embedded copies may be partial.

for a senior

Weigh embedding against cacheability and payload size, and note HAL's lack of action semantics and the HAL-FORMS extension.

for a principal

Decide when HAL's minimalism is the right platform default versus a richer format, and require link generation from routing metadata rather than string building.

## The model HAL (Hypertext Application Language) defines just enough structure to make JSON linkable. A HAL document is a **resource object**: its own state as ordinary JSON members, plus two reserved members whose names begin with an underscore. **_links** - an object whose keys are link relation names and whose values are link objects (or arrays of them). A link object requires href and may carry: - templated: true when href is a URI template that must be expanded before use - type: a hint at the media type of the target - name: a secondary key used to disambiguate multiple links sharing a relation - title: human-readable label - deprecation: a URL explaining that this link is going away **_embedded** - an object whose keys are, again, relation names, and whose values are resource objects or arrays of them. Each embedded resource is a full HAL resource with its own _links and possibly its own _embedded, so documents nest. ## What _embedded is for Without embedding, a collection of a hundred orders is a hundred links and a hundred round trips. _embedded lets the server ship the representations it already has in hand. The relation name says what the embedded things are to the parent (item, author, related), exactly as a link would. Two consequences follow. First, an embedded resource may legitimately be a partial representation - the server may include only the fields worth listing - so clients that need everything follow the embedded resource's own self link. Second, embedding is a caching decision: an embedded copy is frozen inside the parent's cache entry, so highly volatile or independently cacheable sub-resources are often better left as links. ## Single versus array: the classic bug HAL permits a relation's value to be either one object or an array. A collection with one member can serialise as an object and with two as an array, and naive client code that iterates unconditionally breaks at exactly one item. Real clients normalise on read; some servers pin the choice per relation and document it. Expect this as a follow-up question. ## Custom relations and curies Extension relation names are URIs, which is verbose to repeat. HAL provides curies: a reserved link relation holding an array of templated links with name and href, letting documents write ex:approve instead of https://example.com/rels/approve. The client expands the prefix using the curie template to recover the full URI. Curies are a compression device for rel names; they change nothing semantically. ## What HAL does not do HAL has no actions, no methods, no field descriptions. A cancel link tells the client the URL, not that it should POST an empty body. Formats such as Siren, or the HAL-FORMS extension with its _templates member, exist to fill that gap. HAL also imposes no conventions for pagination, filtering, or errors - you layer those on yourself. ## Implementation shape Spring HATEOAS is a common concrete example: RepresentationModel carries the links, EntityModel wraps a payload object, CollectionModel wraps a list, Link and WebMvcLinkBuilder build hrefs from controller methods so they cannot drift from the routing table, and enabling the HAL hypermedia type makes the serializer emit _links and _embedded. That last point is the real value - links derived from the routes rather than string-concatenated.

  • Why is a HAL relation sometimes an object and sometimes an array, and how do clients cope?
    The spec allows both, so a server may emit a single link object for one target and an array when there are several - which means the same relation can change shape with the data. Robust clients normalise every relation to an array immediately after parsing. Servers can reduce the pain by always emitting arrays for relations that are conceptually multi-valued and documenting the choice.
  • When should a related resource be embedded rather than linked?
    Embed when the client almost always needs it and the server already has it, which removes a round trip. Link when the sub-resource is large, volatile, independently cacheable, or only occasionally needed, because an embedded copy is frozen into the parent's cached representation and inflates every response that carries it.

saying these in an interview costs you the question

  • Believing _embedded expresses a different relationship type than _links
  • Assuming a relation is always an array, so single-item responses crash the client
  • Expecting HAL to describe HTTP methods or form fields
  • Treating an embedded partial representation as the complete resource

context

open as a page

How is a JSON:API document (media type application/vnd.api+json) laid out - what goes in data, relationships and included - and what does that structure buy you over ad-hoc JSON?

level: middleimportance: should knowfreq 34%

basics

~20 s

Top level holds data, errors or meta. data is a resource object with type, id, attributes and relationships; relationships hold identifier objects (type plus id) and links; included carries the full related resources, deduplicated. It gives you a normalised graph plus fixed conventions for includes, sparse fields and paging.

open as a page

A HAL document can tell a client where to go but not how to submit a change. What does the Siren media type add with its actions array, and what does the HAL-FORMS extension do about the same gap?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

Siren entities carry an actions array where each action names itself and declares method, href, request content type, and a list of fields with names and types - enough for a client to render and submit a form. HAL-FORMS adds an equivalent _templates member to HAL documents.

open as a page

You are setting the response format for a new family of internal and partner-facing REST services. How would you choose between plain JSON, HAL, JSON:API and Siren, and why do those formats register distinct media types such as application/hal+json instead of just using application/json?

level: principalimportance: nice to knowfreq 24%

basics

~20 s

Choose by client population: plain JSON for lockstep first-party clients, HAL for light linking, JSON:API for graph-shaped entity APIs needing shared conventions, Siren or HAL-FORMS for generic clients that must be told how to act. Distinct media types make the format negotiable, and the +json suffix marks it as JSON-parseable.

open as a page