skip to content

Spring HATEOAS

Spring HATEOAS builds hypermedia responses: representation models, type-safe link building, and HAL with affordances. Interviewers use it to probe how literally you take REST's uniform interface.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

14

What is HAL in Spring HATEOAS, and how does a HAL JSON response differ from a plain JSON response?

level: juniorimportance: must knowfreq 55%

answer

  1. _links + _embedded
  2. application/hal+json
  3. EntityModel / CollectionModel wrap the POJO
  4. linkTo(methodOn(...)).withSelfRel()
  5. starter-hateoas auto-enables

basics

~20 s

HAL (Hypertext Application Language) is a JSON format that adds hyperlinks to a resource under a _links object, plus embedded related resources under _embedded. Its media type is application/hal+json. Plain JSON has only data, no links.

solid answer

~40 s

HAL is a standardized hypermedia JSON format Spring HATEOAS uses to make REST responses navigable. Beyond the resource's own fields, a HAL document carries a `_links` object (each entry has an `href`, keyed by relation name like `self` or `orders`) and optionally an `_embedded` object holding related resources inline. Its media type is `application/hal+json`, and Spring Boot's `spring-boot-starter-hateoas` auto-enables HAL rendering. You build these responses by wrapping domain objects in `EntityModel<T>` or `CollectionModel<T>` and adding links via `WebMvcLinkBuilder.linkTo(methodOn(...)).withSelfRel()`. The value is discoverability: clients follow links by relation name instead of hard-coding URI templates, so the server can change URIs without breaking clients (the HATEOAS constraint of REST).

code

java · 23 lines
java
import org.springframework.hateoas.EntityModel;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;

@RestController
class EmployeeController {

    @GetMapping("/employees/{id}")
    EntityModel<Employee> one(@PathVariable Long id) {
        Employee employee = repository.findById(id).orElseThrow();
        return EntityModel.of(employee,
            linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel(),
            linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));
    }
}

// Produces:
// {
//   "id": 1, "name": "Ada",
//   "_links": {
//     "self":      { "href": "http://localhost/employees/1" },
//     "employees": { "href": "http://localhost/employees" }
//   }
// }

go deeper

for a junior

Know that HAL adds _links/_embedded, the media type is application/hal+json, and you wrap objects in EntityModel.

for a middle

Should build links with WebMvcLinkBuilder.linkTo(methodOn(...)) and understand relation-vs-URI decoupling.

for a senior

Explains auto-configuration via the starter, PagedModel, and the read-only limitation of HAL that motivates HAL-FORMS.

for a principal

Frames HAL as one hypermedia choice among several (HAL-FORMS, Collection+JSON, UBER) and weighs client-coupling tradeoffs for API longevity.

**HATEOAS** stands for *Hypermedia As The Engine Of Application State* — the REST constraint that a response should tell the client what it can do next via links, rather than the client hard-coding URIs. **Spring HATEOAS** is the library that implements this for Spring MVC/WebFlux. **HAL (Hypertext Application Language)** is a concrete, widely-used JSON convention for expressing hypermedia. A HAL document is just JSON with two reserved properties: - `_links`: an object whose keys are *link relations* (`self`, `next`, `orders`, …) and whose values contain at least an `href`. A relation may map to a single link object or an array of them. - `_embedded`: an object holding full representations of related resources inline (again keyed by relation), so a client can avoid extra round-trips. Everything else in the JSON is the resource's own state. The media type is `application/hal+json`, exposed in Spring as `MediaTypes.HAL_JSON`. **How you produce HAL in Spring HATEOAS.** You don't hand-write `_links`. You wrap your domain object in a *representation model*: - `EntityModel<T>` — a single domain object plus links. `EntityModel.of(employee, link1, link2)`. - `CollectionModel<T>` — a collection plus links. - `PagedModel<T>` — a page (adds a `page` metadata block with size/number/totalElements). Links are built type-safely with `WebMvcLinkBuilder`: `linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel()` inspects the controller's `@RequestMapping`/`@GetMapping` to compute the URI, so refactoring a path updates the link automatically. `.withRel("orders")` names a custom relation; `.withSelfRel()` is shorthand for the `self` relation. **Enabling it.** With `spring-boot-starter-hateoas` on the classpath, Boot auto-configures a Jackson module and content negotiation for HAL — no explicit annotation needed. Without Boot you'd add `@EnableHypermediaSupport(type = HypermediaType.HAL)` to a config class. This registers the `Jackson2HalModule` that serializes `RepresentationModel` subclasses into the `_links`/`_embedded` shape. **Edge cases / gotchas.** - The link *relation* is the contract, not the URI. Clients should look up `_links.self.href`, never guess the path. - An empty `CollectionModel` still renders `_embedded` differently across versions; supply the element type (via `CollectionModel.empty()` fallbacks or an assembler) so the relation name is correct. - HAL is *read-oriented*: it tells clients where to go (GET) but not the shape of write requests. For that you need **HAL-FORMS** and the **Affordances API** (separate topics). - A plain `@RestController` returning a POJO produces `application/json` with no `_links`; you only get HAL when you return a `RepresentationModel` subtype and HAL support is enabled. **When to use.** HAL fits public or long-lived APIs where you want clients decoupled from URI structure and self-describing navigation. It adds ceremony, so trivial internal APIs often skip it.

  • What is the difference between a link relation and an href, and why does it matter to clients?
    The relation (e.g. `self`, `orders`) is the stable, semantic key the client keys off; the href is the URI, which the server may change. Clients follow relations, so URI changes don't break them.
  • What does `_embedded` give you that `_links` does not?
    `_embedded` inlines the full representation of related resources so the client avoids extra HTTP round-trips, whereas `_links` only points to where a related resource lives.

saying these in an interview costs you the question

  • Claiming HAL requires you to manually write the `_links` JSON.
  • Thinking a plain POJO returned from `@RestController` is automatically HAL.
  • Saying clients should read the href to figure out routing instead of following relations.
  • Confusing HAL (`application/hal+json`) with plain `application/json`.

context

open as a page

What is RepresentationModel and EntityModel<T> in Spring HATEOAS, and why would you use EntityModel instead of adding links directly to your DTO?

level: juniorimportance: must knowfreq 70%

basics

~10 s

RepresentationModel is the base class that carries hypermedia links. EntityModel<T> wraps a single domain object plus its links, so you can attach links without changing or extending your original DTO class.

open as a page

What is a RepresentationModelAssembler and why would you use one instead of building links inline in the controller?

level: middleimportance: should knowfreq 45%

basics

~10 s

RepresentationModelAssembler<T, D> is a component that converts a domain entity T into a link-bearing model D (usually EntityModel<T>). It centralizes link-building so controllers and other places produce identical representations instead of duplicating link code.

open as a page

What is CollectionModel<T> and how does it differ from returning a plain list? What does its HAL output look like?

level: middleimportance: should knowfreq 55%

basics

~10 s

CollectionModel<T> wraps a collection of items so the whole collection can carry its own hypermedia links (like a self link). In HAL the items go under _embedded and collection-level links under _links.

open as a page

Explain the Affordances API in Spring HATEOAS: what `afford(...)` does and how affordances relate to HAL-FORMS.

level: seniorimportance: should knowfreq 35%

basics

~10 s

An affordance describes an action you can take on a resource (e.g. update, delete) attached to a link. You add one with afford(methodOn(controller).method(...)). Affordances render as HAL-FORMS _templates; plain HAL ignores them.

open as a page

How does HAL-FORMS differ from HAL, and how does Spring HATEOAS decide which one to render?

level: seniorimportance: should knowfreq 30%

basics

~10 s

HAL describes navigation with _links. HAL-FORMS is a superset that also adds _templates describing how to perform write operations (method + properties). Spring picks one via content negotiation on the request's Accept header.

open as a page

What is PagedModel<T>, how does it differ from CollectionModel, and how do you build one from a Spring Data Page?

level: seniorimportance: should knowfreq 50%

basics

~10 s

PagedModel<T> is a CollectionModel that also carries page metadata (size, totalElements, totalPages, number) and navigation links (first/prev/next/last). You usually build it from a Spring Data Page using PagedResourcesAssembler.toModel(page, assembler).

open as a page

When would you adopt HAL/HAL-FORMS with affordances for a production API, and what are the tradeoffs versus a plain JSON API with OpenAPI?

level: principalimportance: nice to knowfreq 18%

basics

~10 s

Adopt HAL/HAL-FORMS when you want clients decoupled from URIs and able to discover navigation and write operations at runtime. Tradeoff: more server-side ceremony and heavier payloads versus OpenAPI's build-time, tooling-rich but statically-coupled contract.

open as a page

Design decision: when should you extend RepresentationModel<T> for your own type versus wrapping domain objects in EntityModel<T>/CollectionModel<T>? What are the trade-offs?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Extend RepresentationModel when you own a dedicated, strongly-typed API model and want compile-time fields plus links in one class. Wrap with EntityModel/CollectionModel to keep domain/DTO classes free of HATEOAS and add links only at the edge.

open as a page