Allow to define HAL FORMS options based on the representation model's state
At the moment options can only be added via HalFormsConfiguration for certain input classes' properties. It would be more flexible when PropertyMetadata would support it too, because there are use cases where a class and property based approach is not sufficient:
- Dependent on a certain state only a subset of options are allowed: order amount > 1000 $ -> shipping only via UPS, not via FedEx
- List/Array types: property or Parameter of type List<Long>
There are two challenges to that:
- Options are a HAL FORMS specific concept. Affordances don't know about that and unfortunately can't as we cannot expect every hypermedia type to support that concept, especially all details around the way HAL FORMS models them.
- The
HalFormsOptionscreation currently doesn't see theRepresentationModel– i.e. the state of the resource – at all. This is primarily driven by the idea that affordances are subject to a different lifecycle and everything state-specific would rather end up in the definition which affordance is added to the model in the first place.
I can see that the second point is a limitation and that we should improve on that. That said, I wonder what kind of API you'd like to see to apply representation model-specific rules to the options? We could allow users to post-process the statically computed options, but that would require us to expose API to inspect the inline and remote options. Also, we'd have to make the API work based on RepresentationModel but that doesn't even know about any kind of payload. So, to be explicit about the actual type (model + payload) you're interested in, we need to expose API to capture that, which usually doesn't look very elegant but yeah.
OK, understood.
But why every media type has to support every affordance property? Other types than HAL-FORMS could easily ignore this property? Maybe it is already the case? I do not know how UBER oder CollectionJson, which are currently supported, handle all these possible attributes on PropertyMetadata.
But maybe I am to focused on HAL-FORMS because this is the only type I am working with.
It doesn't have to. But we can't simply add everything we see in HAL FORMS to the general affordance abstraction, as that would just create a kitchen sink of everything that every hypermedia type in the world would expose. That doesn't lead to usable APIs (in terms of Spring HATEOAS APIs) and – even more problematic – is not resulting in software reasonably maintainable.
But maybe I am to focused on HAL-FORMS because this is the only type I am working with.
That seems to be the case indeed. Rest assured that quite a lot of thinking went into the current arrangement to carefully balance the need of individual media types and finding decent abstractions for the source metadata. It might be worth studying the package arrangement to realize that everything specific to hypermedia types is located in the individual sub-packages of mediatypes. All of them are usually implemented by registering an AffordanceModelFactory from a ConfiguredAffordance. Media type-specific serializers for RepresentationModel then access the AffordanceModel and prepare the actual DTOs to be rendered by Jackson according to the media type-specification. That has worked quite well so far for a variety of media types.
In 2, we have identified a fundamental limitation of the design of the HAL FORMS options implementation, which we can definitely work on to get resolved. Let's stick with that for this ticket. Any kind of input for the API design challenges appreciated.
Now it is like this: org.springframework.hateoas.mediatype.hal.forms.HalFormsPropertyFactory.createProperties(HalFormsAffordanceModel model)
Could be: org.springframework.hateoas.mediatype.hal.forms.HalFormsPropertyFactory.createProperties(HalFormsAffordanceModel model, RepresentationModel<?> resource)
Then the HalFormsOptionsFactory could offer a new withOptions method which accepts also the resource as a parameter and a HalFormsOptions creator could use the resource state to create the options.
@odrotbohm ,
Could we, as a first step, provide the affordance link to HalFormsOptionsFactory#getOptions? That would unlock some dynamic cases where a PathVariable constrains the allowed options.
Maybe it could be an additional argument to this call? https://github.com/spring-projects/spring-hateoas/blob/b19f7de6d329f728e09cbb294c753ffd6c1d5d50/src/main/java/org/springframework/hateoas/mediatype/hal/forms/HalFormsPropertyFactory.java#L86
Or maybe it could be added to InputPayloadMetadata ?