From spring
Build Spring hypermedia representations with links, assemblers, HAL output, affordances, and paged models. Use this skill when building Spring hypermedia representations with links, assemblers, HAL output, affordances, and paged models for server responses.
npx claudepluginhub ririnto/sinon --plugin springThis skill uses the workspace's default tool permissions.
Use this skill when building Spring hypermedia representations with links, assemblers, HAL output, affordances, and paged models for server responses.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Use this skill when building Spring hypermedia representations with links, assemblers, HAL output, affordances, and paged models for server responses.
Use spring-hateoas for link modeling, representation assembly, hypermedia media types, and affordance exposure on the server side.
The ordinary Spring HATEOAS job is:
_links and embedded data shape.| Surface | Start here when | Open a reference when |
|---|---|---|
| Plain HAL item and collection responses | one controller returns EntityModel or CollectionModel | stay in SKILL.md |
| Page navigation and page metadata | clients depend on prev/next/first/last or strict page metadata semantics | open references/pagedmodel-navigation-and-page-metadata.md |
| HAL-FORMS or affordances | clients need action metadata or _templates | open references/hal-forms-and-affordances.md |
| Aggregate-type link derivation | explicit hypermedia activation or EntityLinks is the blocker | open references/entity-links-and-hypermedia-support.md |
| Cross-cutting link enrichment | one shared rule must enrich many models after assembly | open references/representation-processors.md |
| Reverse-proxy link correctness | generated host, scheme, or base path is wrong | open references/forwarded-headers-and-proxy-configuration.md |
| Problem Details error payloads | the error path needs application/problem+json | open references/problem-details-error-representations.md |
| Situation | Use |
|---|---|
| One item with links | EntityModel<T> |
| Collection with top-level links | CollectionModel<T> |
| Page result with navigation metadata | PagedModel<T> |
Keep link relation names stable and model the representation type the client actually consumes rather than returning domain entities directly.
Use the Boot starter for ordinary HATEOAS work.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
</dependencies>
The Boot starter is the ordinary activation path. Open the entity-links reference only when the application needs explicit @EnableHypermediaSupport, EntityLinks, or aggregate-type-based link derivation.
| Need | Artifact |
|---|---|
| HAL item, collection, and paged responses | spring-boot-starter-hateoas |
| HAL-FORMS and affordances | spring-boot-starter-hateoas |
| EntityLinks and explicit hypermedia activation | spring-boot-starter-hateoas |
./mvnw test -Dtest=OrderRepresentationTests
./gradlew test --tests OrderRepresentationTests
Content-Type: application/hal+json
{
"_embedded": {},
"_links": {},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
Default to HAL unless the project already committed to another hypermedia format.
RepresentationModelAssembler for item and collection representations so link logic is centralized.Use an assembler for resource-specific links and use a RepresentationModelProcessor only when one cross-cutting rule must enrich many representations the same way.
Keep aggregate-type-based link derivation separate from ordinary assembler work. Open the entity-links reference only when controller-method links are no longer the right source of truth.
class OrderModel extends RepresentationModel<OrderModel> {
private final long id;
private final String status;
OrderModel(long id, String status) {
this.id = id;
this.status = status;
}
}
class OrderModelAssembler implements RepresentationModelAssembler<Order, OrderModel> {
@Override
public OrderModel toModel(Order order) {
OrderModel model = new OrderModel(order.id(), order.status());
model.add(linkTo(methodOn(OrderController.class).one(order.id())).withSelfRel());
model.add(linkTo(methodOn(OrderController.class).all()).withRel("orders"));
return model;
}
@Override
public CollectionModel<OrderModel> toCollectionModel(Iterable<? extends Order> orders) {
CollectionModel<OrderModel> models = RepresentationModelAssembler.super.toCollectionModel(orders);
models.add(linkTo(methodOn(OrderController.class).all()).withSelfRel());
return models;
}
}
@RestController
class OrderController {
private final OrderService service;
private final OrderModelAssembler assembler;
OrderController(OrderService service, OrderModelAssembler assembler) {
this.service = service;
this.assembler = assembler;
}
@GetMapping("/orders/{id}")
OrderModel one(@PathVariable long id) {
return assembler.toModel(service.find(id));
}
@GetMapping("/orders")
CollectionModel<OrderModel> all() {
return assembler.toCollectionModel(service.findAll());
}
}
PagedModel<OrderModel> model = pagedResourcesAssembler.toModel(page, assembler);
Link self = linkTo(methodOn(OrderController.class).one(order.id())).withSelfRel();
Link update = self.andAffordance(afford(methodOn(OrderController.class).update(order.id(), null)));
Use affordances only when clients or generated UI flows will actually consume them.
@WebMvcTest(OrderController.class)
class OrderRepresentationTests {
@Autowired
MockMvc mvc;
@Test
void orderResponseContainsSelfLink() throws Exception {
mvc.perform(get("/orders/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$._links.self.href").exists());
}
}
{
"id": 1,
"status": "CREATED",
"_links": {
"self": {
"href": "/orders/1"
},
"orders": {
"href": "/orders"
}
}
}
{
"_links": {
"self": {
"href": "/orders"
}
}
}
self
orders
self link and any collection or action links the client expects._links, broken relation names, or malformed representation shapes as contract failures.Return:
_links and embedded dataEntityLinks, or explicit @EnableHypermediaSupport configuration is required.prev/next/first/last navigation links or precise page metadata semantics.application/problem+json instead of ad hoc JSON payloads.