Lightweight HATEOAS library designed for Spring WebFlux.
hateoflux is a lightweight, reactive-first Java library designed to streamline the creation of hypermedia-driven APIs in Spring WebFlux applications. It addresses the limitations of Spring HATEOAS in reactive environments, offering a more intuitive and maintainable approach to building HAL+JSON compliant APIs.
Getting Started | Cookbook | Documentation | Demos
- Why hateoflux?
- Features
- Getting Started
- Basic Usage
- Advanced Usage
- Examples & Use Cases
- Documentation
- Comparison with Spring HATEOAS
- Contributing
- License
- Contact
Building hypermedia-driven APIs in reactive Spring applications using WebFlux can be challenging with traditional libraries like Spring HATEOAS, which are primarily designed for Spring MVC. hateoflux offers a reactive-first solution tailored specifically for Spring WebFlux, simplifying hypermedia API development by:
- Keeping Domain Models Clean: Uses resource wrappers to decouple domain models from hypermedia concerns.
- Reducing Boilerplate: Simplifies assemblers and automates link creation.
- Enhancing Pagination Handling: Provides built-in support for pagination with
HalListWrapper
. - Focused Documentation: Offers comprehensive guidance and examples for reactive environments.
- Resource Wrappers:
HalResourceWrapper
andHalListWrapper
to encapsulate resources and collections. - Type-Safe Link Building: Easily create and manage hypermedia links.
- Specialized Response Types: Purpose-built reactive response handling with
HalResourceResponse
,HalMultiResourceResponse
, andHalListResponse
. - Pagination Support: Simplified pagination with metadata and navigation links.
- URI Template Support: Define dynamic URLs with placeholders.
- Seamless Spring Integration: Works effortlessly with existing Spring configurations and annotations.
- Assembler Interfaces: Reduce boilerplate with
FlatHalWrapperAssembler
andEmbeddingHalWrapperAssembler
.
Before integrating hateoflux into your project, ensure that you have the following installed:
- Java 17 or higher: Ensure that your development environment is set up with Java 17+.
- Gradle 8.5 or higher: Required for building and managing project dependencies.
- Spring Boot 3.0.0 or higher: hateoflux is compatible with Spring Boot 3.0.0+ for seamless integration.
To include hateoflux in your Spring WebFlux project, add it as a dependency using your preferred build tool.
Note: Check the latest available version on Maven Central.
<dependency>
<groupId>de.kamillionlabs</groupId>
<artifactId>hateoflux</artifactId>
<version>latest-version</version>
</dependency>
dependencies {
implementation 'de.kamillionlabs:hateoflux:latest-version'
}
Here's a simple example of how to create a HalResourceWrapper
for an OrderDTO
without any embedded resources.
@GetMapping("/order-no-embedded/{orderId}")
public Mono<HalResourceWrapper<OrderDTO, Void>> getOrder(@PathVariable int orderId) {
Mono<OrderDTO> orderMono = orderService.getOrder(orderId);
return orderMono.map(order -> HalResourceWrapper.wrap(order)
.withLinks(
Link.of("orders/{orderId}/shipment")
.expand(orderId)
.withRel("shipment"),
Link.linkAsSelfOf("orders/" + orderId)
));
}
Serialized Output
{
"id": 1234,
"userId": 37,
"total": 99.99,
"status": "Processing",
"_links": {
"shipment": {
"href": "orders/1234/shipment"
},
"self": {
"href": "orders/1234"
}
}
}
hateoflux provides specialized response types (basically reactive ResponseEntity
s) to handle different resource scenarios in reactive applications. The following controller method is from the previous example now altered however to return a reactive HTTP response, while preserving the same body:
hateoflux provides specialized response types (essentially reactive ResponseEntity
s) to handle different resource scenarios in reactive applications. Here's the previous controller example modified to return a reactive HTTP response while preserving the same body:
@GetMapping("/order-no-embedded/{orderId}")
public HalResourceResponse<OrderDTO, Void> getOrder(@PathVariable String orderId) {
Mono<HalResourceWrapper<OrderDTO, Void>> order = orderService.getOrder(orderId)
.map(order -> HalResourceWrapper.wrap(order)
.withLinks(
Link.of("orders/{orderId}/shipment")
.expand(orderId)
.withRel("shipment"),
Link.linkAsSelfOf("orders/" + orderId)
));
return HalResourceResponse.ok(order)
.withContentType(MediaType.APPLICATION_JSON)
.withHeader("Custom-Header", "value");
}
The library provides three response types for different scenarios:
HalResourceResponse
: For single HAL resources (shown above)HalMultiResourceResponse
: For streaming multiple resources individuallyHalListResponse
: For collections as a single HAL document, including pagination
Assemblers in hateoflux reduce boilerplate by handling the wrapping and linking logic. Implement either FlatHalWrapperAssembler
for resources without embedded entities or EmbeddingHalWrapperAssembler
for resources with embedded entities.
@Component
public class OrderAssembler implements EmbeddingHalWrapperAssembler<OrderDTO, ShipmentDTO> {
@Override
public Class<OrderDTO> getResourceTClass() {
return OrderDTO.class;
}
@Override
public Class<ShipmentDTO> getEmbeddedTClass() {
return ShipmentDTO.class;
}
@Override
public Link buildSelfLinkForResource(OrderDTO order, ServerWebExchange exchange) {
return Link.of("order/" + order.getId())
.prependBaseUrl(exchange);
}
@Override
public Link buildSelfLinkForEmbedded(ShipmentDTO shipment, ServerWebExchange exchange) {
return Link.of("shipment/" + shipment.getId())
.prependBaseUrl(exchange)
.withHreflang("en-US");
}
@Override
public Link buildSelfLinkForResourceList(ServerWebExchange exchange) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
return Link.of("order{?userId,someDifferentFilter}")
.expand(queryParams)
.prependBaseUrl(exchange);
}
}
Leverage the SpringControllerLinkBuilder
for type-safe, annotation-aware link creation.
import static de.kamillionlabs.hateoflux.linkbuilder.SpringControllerLinkBuilder.linkTo;
Link userLink = linkTo(UserController.class, controller -> controller.getUser("12345"))
.withRel(IanaRelation.SELF);
Explore practical examples and debug them in the hateoflux-demos repository. Fork the repository and run the applications to see hateoflux in action.
Refer to the Cookbook: Examples & Use Cases for detailed and explained scenarios and code snippets demonstrating various functionalities of hateoflux.
Comprehensive documentation is available at https://hateoflux.kamillionlabs.de (english), covering:
- What is hateoflux?
- Representation Model
- Response Types
- Link Building
- Assemblers
- Spring HATEOAS vs. hateoflux
- Cookbook: Examples & Use Cases
hateoflux is specifically designed for reactive Spring WebFlux applications, offering a more streamlined and maintainable approach compared to Spring HATEOAS in reactive environments. Key differences include:
Aspect | Spring HATEOAS (WebFlux) | hateoflux |
---|---|---|
Representation Models | Uses wrappers and inheritance-based models, requiring manual embedding of resources via inheritance or separate classes. | Uses wrappers exclusively to keep domain models clean and decoupled. |
Response Types | Uses standard ResponseEntity with manual reactive flow handling |
Dedicated response types optimized for different resource scenarios |
Assemblers and Boilerplate | Verbose with manual resource wrapping and link addition. | Simplified with built-in methods; only links need to be specified in assemblers. |
Pagination Handling | Limited support in reactive environments; requires manual implementation. | Easy pagination with HalListWrapper; handles metadata and navigation links automatically. |
Documentation Support | Better for Spring MVC; less comprehensive for WebFlux. | Tailored for reactive Spring WebFlux with focused documentation and examples. |
Media Types | Supports multiple media types (HAL, Collection+JSON, etc.). | Only supports HAL+JSON for simplicity and performance. |
Affordance & CURIE Support | Supports affordances and CURIEs. | Does not support affordances or CURIEs. |
For a detailed comparison, refer to the Spring HATEOAS vs. hateoflux documentation.
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a new branch for your feature or bugfix.
- Commit your changes with clear messages.
- Submit a pull request detailing your changes.
- For more details, see the CONTRIBUTING.md file.
Note: All pull requests are subject to code review. Please be patient and responsive to any feedback or requests for changes.
For more details, see the CONTRIBUTING.md file.
This project is licensed under the Apache License 2.0. The Apache 2.0 License allows you to freely use, modify, and distribute the software, provided that you include the original license and notices in any copies or substantial portions of the software.
If you have any questions, suggestions, or need support, please feel free to open a discussion, submit an issue, or email us directly at contact@kamillionlabs.de.