For the rest interface the Spring MVC + RxJava + DeferredResult returned from controllers is used.
I am thinking about adding Hateoas support to the endpoints. The natural choice would be the Spring Hateoas. The problem is that Spring Hateoas would not work in the asynchronous/multi-threading environment since it uses ThreadLocal.
Is there any way to workaround that constraint? I do not think so but maybe someone has any suggestions.
Has anyone used other APIs to add Hateoas support to the rest endpoints?
Thank you.
Building REST APIs that follow HATEOAS principle is not easy. So Spring HATEOAS provides some APIs that ease the creation of hypermedia links in API responses (links in JSON documents). It works well with Spring MVC and Spring Data JPA and supports for hypermedia formats like HAL (Hypertext Application Language).
DeferredResult, available from Spring 3.2 onwards, assists in offloading a long-running computation from an http-worker thread to a separate thread. Although the other thread will take some resources for computation, the worker threads are not blocked in the meantime and can handle incoming client requests.
DeferredResult provides an alternative to using a Callable for asynchronous request processing. While a Callable is executed concurrently on behalf of the application, with a DeferredResult the application can produce the result from a thread of its choice.
So the solution I've used is to closure in the request attributes and then apply them as part of a lift operator
public class RequestContextStashOperator<T> implements Observable.Operator<T, T> {
private final RequestAttributes attributes;
/**
* Spring hateoas requires the request context to be set but observables may happen on other threads
* This operator will reapply the context of the constructing thread on the execution thread of the subscriber
*/
public RequestContextStashOperator() {
attributes = RequestContextHolder.currentRequestAttributes();
}
@Override
public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
return new Subscriber<T>() {
@Override
public void onCompleted() {
subscriber.onCompleted();
}
@Override
public void onError(Throwable e) {
subscriber.onError(e);
}
@Override
public void onNext(T t) {
RequestContextHolder.setRequestAttributes(attributes);
subscriber.onNext(t);
}
};
}
}
which you can then use on an observable like
lift(new RequestContextStashOperator<>())
as long as the object is created in the same thread as the request. You can then use a map after in the observable chain to map your object up to being a resource and add your hateoas links in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With