brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
spring-hateoasSpring HATEOAS for building hypermedia-driven RESTful APIs. Covers EntityModel, CollectionModel, RepresentationModelAssembler, HAL, and affordances. USE WHEN: user mentions "HATEOAS", "hypermedia", "HAL", "EntityModel", "CollectionModel", "RepresentationModelAssembler", "Richardson Maturity Level 3" DO NOT USE FOR: simple REST APIs without hypermedia - us…
Independent GitHub snapshot · Automated classification · Original documentation governs
name: spring-hateoas description: | Spring HATEOAS for building hypermedia-driven RESTful APIs. Covers EntityModel, CollectionModel, RepresentationModelAssembler, HAL, and affordances.
USE WHEN: user mentions "HATEOAS", "hypermedia", "HAL", "EntityModel", "CollectionModel", "RepresentationModelAssembler", "Richardson Maturity Level 3"
spring-graphql skill
allowed-tools: Read, Grep, Glob, Write, EditFull Reference: See advanced.md for affordances (HAL-FORMS), embedded resources, link relations, media types, and testing patterns.
Deep Knowledge: Use
mcp__documentation__fetch_docswith technology:spring-hateoasfor comprehensive documentation.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
Richardson Maturity Model:
Level 0: Plain Old XML/JSON (single endpoint)
Level 1: Resources (multiple endpoints)
Level 2: HTTP Verbs (GET, POST, PUT, DELETE)
Level 3: Hypermedia Controls (HATEOAS) ← This!
@GetMapping("/users/{id}")
public EntityModel<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(id)).withSelfRel(),
linkTo(methodOn(UserController.class).getAllUsers()).withRel("users"),
linkTo(methodOn(OrderController.class).getOrdersByUser(id)).withRel("orders")
);
}
{
"id": 1,
"name": "John Doe",
"_links": {
"self": { "href": "http://localhost:8080/api/users/1" },
"users": { "href": "http://localhost:8080/api/users" },
"orders": { "href": "http://localhost:8080/api/users/1/orders" }
}
}
@GetMapping("/users")
public CollectionModel<EntityModel<User>> getAllUsers() {
List<User> users = userService.findAll();
List<EntityModel<User>> userModels = users.stream()
.map(user -> EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel()
))
.toList();
return CollectionModel.of(userModels,
linkTo(methodOn(UserController.class).getAllUsers()).withSelfRel()
);
}
@Component
public class UserModelAssembler implements RepresentationModelAssembler<User, EntityModel<User>> {
@Override
public EntityModel<User> toModel(User user) {
return EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel(),
linkTo(methodOn(UserController.class).getAllUsers()).withRel("users")
);
}
}
// Usage
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
private final UserModelAssembler assembler;
@GetMapping("/{id}")
public EntityModel<User> getUser(@PathVariable Long id) {
return assembler.toModel(userService.findById(id));
}
@GetMapping
public CollectionModel<EntityModel<User>> getAllUsers() {
return assembler.toCollectionModel(userService.findAll());
}
}
@GetMapping("/users")
public PagedModel<EntityModel<User>> getAllUsers(
@PageableDefault(size = 20) Pageable pageable,
PagedResourcesAssembler<User> pagedAssembler) {
Page<User> users = userService.findAll(pageable);
return pagedAssembler.toModel(users, userModelAssembler);
}
| Do | Don't |
|---|---|
| Use ModelAssembler pattern | Build links inline everywhere |
| Include self links always | Omit navigation links |
| Use standard IANA relations | Invent new relation names |
| Add conditional links for actions | Show all links regardless of state |
spring-graphql instead| Anti-Pattern | Problem | Solution |
|---|---|---|
| Building links inline | Duplicated code everywhere | Use RepresentationModelAssembler |
| Missing self links | Clients can't identify resources | Always add withSelfRel() |
| Hardcoded URLs | Breaks on deployment | Use linkTo/methodOn builders |
| Inventing relations | Non-standard, hard to understand | Use IANA link relations |
| Problem | Diagnostic | Fix |
|---|---|---|
| Links not serialized | Check Accept header | Ensure HAL media type |
| NullPointerException in linkTo | Check controller method | Verify method signature matches |
| Wrong base URL | Check proxy config | Configure server.forward-headers-strategy |
| Pagination links missing | Check assembler | Use PagedResourcesAssembler |